What's the right way to check if collection.find success in Meteor? - meteor

The Meteor document said 'find returns a cursor', and can use 'fetch' to return all matching documents, but I didn't find a complete reference of this 'cursor' object.
I want to use this 'cursor' object to check if find sucessfully got some result or got nothing.
Following is what I am doing now:
if (Tags.find({name: tag["tag"]}).fetch().length === 0) {
// Not found, add default documents
}
Not sure if this is right way(best practice) to do this?

The idiom is to use .findOne:
if (!Tags.findOne(...)) {
// nothing found, add default documents
}
This is more efficient than fetch() because it only queries the database for one document.
You can also use <cursor>.count, but beware that in Mongo, count operations are expensive.

Related

Firestore Update fields in nested objects with dynamic key

I need to update a field in a nested object with a dynamic key.
the path could look like this: level1.level2.DYNAMIC_KEY : updatedValue
The update-method deletes everything else on level1 instead of only updating the field in the nested object. The update() acts more like a set(). What am I doing wrong?
I tried the following already:
I read the documentation https://firebase.google.com/docs/firestore/manage-data/add-data#update-data
but that way it is a) static and b) still deletes the other fields.
Update fields in nested objects
If your document contains nested objects, you can use "dot notation" to reference nested fields within the document when you call update()
This would be static and result in
update({
'level1.level2.STATIC_KEY' : 'updatedValue'
});
Then I found this answer https://stackoverflow.com/a/47296152/5552695
which helped me to make the updatepath dynamic.
The desired solution after this could look like
field[`level1.level2.${DYNAMIC_KEY}`] = updateValue;
update(field);
But still: it'll delete the other fields in this path.
UPDATE:
The Structure of my Doc is as follows:
So inside this structure i want to update only complexArray > 0 > innerObject > age
Writing the above path into the update() method will delete everything else on the complexArray-level.
A simple update on first-level-fields works fine and lets the other first-level-fields untouched.
Is it possible, that firestore functions like update() can only act on the lowest field-level on an document. And as soon as i put complex objects into an document its not possible to select such inner fields?
I know there would be the solution to extract those "complex" objects into separate collections + documents and put these into my current lowest document level. I think this would be a more accurate way to stick to the FireStore principles. But on Application side it is easier to work with complex object than to always dig deeper in firestore collection + document structure.
So my current solution is to send the whole complex object into the update() method even though I just changed only one field on application side.
Have you tried using the { merge: true } option in your request?
db
.collection("myCollection")
.doc("myDoc")
.set(
{
level1: { level2: { myField: "myValue" } }
},
{ merge: true }
)

Meteor - check() VS new SimpleSchema() for verifying .publish() arguments

To ensure the type of the arguments my publications receive, should I use SimpleSchema or check()?
Meteor.publish('todos.inList', function(listId, limit) {
new SimpleSchema({
listId: { type: String },
limit: { type: Number }
}).validate({ listId, limit });
[...]
});
or
Meteor.publish('todos.inList', function(listId, limit) {
check(listId, String);
check (limit, Number);
[...]
});
check() allows you to check data type, which is one thing, but is somewhat limited.
SimpleSchema is much more powerful as it checks all keys in a documents (instead of one at a time) and lets you define not only type but also allowed values, define default (or dynamic) values when not present.
You should use SimpleSchema this way:
mySchema = new SimpleSchema({ <your schema here>});
var MyCollection = new Mongo.Collection("my_collection");
MyCollection.attachSchema(mySchema);
That way, you don't event need to check the schema in methods: it will be done automatically.
Of course it's always good practice to use the
mySchema.validate(document);
to validate a client generated document before inserting it in your collection, but if you don't and your document doesn't match the schema (extra keys, wrong types etc...) SimpleSchema will reject the parts that don't belong.
To check arguments to a publish() function or a Meteor.method() use check(). You define a SimpleSchema to validate inserts, upserts, and updates to collections. A publication is none of those - it's readonly. Your use of SimpleSchema with .validate() inline would actually work but it's a pretty unusual pattern and a bit of overkill.
You might find this helpful.
CHECK is a lightweight package for argument checking and general pattern matching. where as SimpleSchema is a huge package with one of the check features. It is just that one package was made before the other.
Both works the same. You can use CHECK externally in Meteor.methods as well. Decision is all yours.
Michel Floyd answer's, made me realize that check() actually sends Meteor.Error(400, "Match Failed") to the client, while SimpleSchema within Methods sends detailed ValidationError one can act upon to display appropriate error messages on a form for instance.
So to answer the question : should we use check() or SimpleSchema() to assess our arguments types in Meteor, I believe the answer is :
Use SimpleSchema if you need a detailed report of the error from the client, otherwise check() is the way to go not to send back critical info.

Meteor parameters and where they come from

I have a question where all the parameters for the meteor functions are coming from? Things like postAttribues, id, postId, limit, etc, etc...
Meteor.publish('newPosts', function(limit) {
return Posts.find({}, {sort: {submitted: -1}, limit: limit});
});
Meteor.publish('singlePost', function(id) {
return id && Posts.find(id);
});
//related to post
Meteor.publish('comments', function(postId) {
return Comments.find({postId: postId});
});
Are they signaled from Mongo DB? It's fine and dandy to memorize these things, but it would be nice to know where these parameters are coming from and what parameters are usually available to me.
I never used any frameworks before, so this may be why I'm confused. I worked exclusively with Javascript before jumping on Meteor.
I also have the same question about Iron Router: When creating a route, we can set a route with a specific Id with /randomName/:_id and the unique code that's responsible for associating the ":_Id" with the actual page is this.params._id. Why and how does the back end associate these things?
I would appreciate any help to help me understand this better.
A meteor find() query follows the syntax find({query}, {options}) defined here: http://docs.meteor.com/#/full/find where the options parameter is an object containing sort, limit, etc... These options look similar to some Mongo operators such as .sort() and .limit() but are defined
The parameters limit and sort are part of the options parameter. It would be useful to review the documentation for Meteor found here: https://docs.mongodb.org/manual/
The parameter postId comes from the way you have defined your objects in your DB. This field is part of your query parameter which specifies what exactly to find in the DB. So by specifying a postId:, Meteor will look through your Comments collection for any containing the postId that you pass. When you pass a string as the query parameter, it is expected that that string is an _id in your collection.
For the parameters being passed into the publication itself see docs.meteor.com/#/full/meteor_subscribe . It comes from the subscription. Basically, you can pass. Parameters between the client and the server this way. To make your publication more robust, you can add parameters as you wish so that the client can specify which 'id' or 'limit' that they want.
As for your iron:router question, I am not sure exactly what you are asking about how the backend associates parameters and the page itself. Perhaps you could be more specific and update your question accordingly

Meteor filter collection

I'm trying to secure accessing a specific collection but I'm having troubles doing it. I have no problems disabling the insert, update and delete with the Collection.allow() map.
The problem is that I also want to filter the results returned by the Collection.find() and Collection.findOne() function. I read about the Meteor.publish() and Meteor.subscribe() stuff, but somehow I cannot make it work (it's not getting filtered, I just can see all the results).
In my server-code I do the following:
Groups = new Meteor.Collection("groups");
Meteor.publish("myGroups", function() {
if (Functions.isAdmin(userId)) {
return Groups.find({
sort: {
name: 1
}
});
}
});
The function I'm using really works (so it's not that it's always returning true).
In the client-code I wrote the following:
Meteor.subscribe("myGroups");
Groups = new Meteor.Collection("groups");
Now when I do Groups.find{}); at the client I still get all results (and I should get no result).
Am I misunderstanding something or doing something wrong? I could of course make the collection completely server-side and use Meteor.methods() and Meteor.call() to get the collection data (so that it's always encapsulated by the server). But I really thought it would be cool that I didn't have to do that.
Also I wonder why this can't be done on the same level as insert/update/remove with Collection.allow(). I mean, it would be could that we could have the possibility to add a filter to the map for reading data through find/findOne.
Like #Tarang said, removing autopublish by executing the following command works:
meteor remove autopublish

CouchDB "_changes" listener updates the doc, which triggers another change

I want to write a background program that will monitor the _changes feed of a CouchDB, and possibly update the document. The problem is that the update causes another _change, and I get an endless loop! What's the best way to avoid this?
For example, here is the specific scenario: I have a CouchApp where users modify documents through their browser. I also have a python program that creates a PDF version of a document and then attaches it as an attached file to the document itself. My problem is that doing the PUT Attachment to upload the PDF also triggers a document change. I have to be able to tell whether a change is being caused by the PDF upload, or not. It seems like it should be easy, but I can't think of a simple way to do it. I would rather keep the PDF generator program be "stateless", keeping any required state in the db itself.
Now, this can easily be done if I require that users who change the document set some sort of flag on the document to indicate that it needs to be processed. The trick is how to do it without requiring that.
I have come to the conclusion that a "_changes" listener should never modify the document that it listens to. In my case I decided to attach my PDF file to a separate document, in a separate "database" within couchdb, but using the same "_id" to make it easy to correlate. That way I don't trigger a "_change" on the same documents that I am listening to. I could not get past the need to require every client that changes the document to somehow "flag" it as requiring processing ( by deleting the existing attachment, or otherwise setting some "dirty" flag ). After much pondering, I think that this will be a rule-of-thumb for me : that you must not modify a document upon receiving a "_change" notification for that document. Has anyone else reached the same conclusion?
Use a filter function and and filter out the second change – either by the document structure change or by setting an additional flag to the changed document:
function(doc, req)
{
if(!doc.hasStructuralChange) { //fix this
return true;
}
return false;
}
or
function(doc, req)
{
if(!doc.changed) { //set doc.changed during first update
return true;
}
return false;
}
Edit: You can check for an attachment via if (doc._attachments)

Resources