Meteor.Collection and Meteor.Collection.Cursor - mongodb

What is
Meteor.Collection
and
Meteor.Collection.Cursor
?
How does these two related to each other? Did:
new Meteor.Collection("name")
create a MONGODB collection with the parameter name?

Did new Meteor.Collection("name") create a MONGODB collection with the parameter name?
Not exactly. A Meteor.Collection represents a MongoDB collection that may or may not exist yet, but the actual MongoDB collection isn't actually created until you insert a document.
A Meteor.Collection.Cursor is a reactive data source that represents a changing subset of documents that exist within a MongoDB collection. This subset of documents is specified by the selector and options arguments you pass to the Meteor.Collection.find(selector, options) method. This find() method returns the cursor object. I think the Meteor Docs explain cursors well:
find returns a cursor. It does not immediately access the database or return documents. Cursors provide fetch to return all matching documents, map and forEach to iterate over all matching documents, and observe and observeChanges to register callbacks when the set of matching documents changes.
Collection cursors are not query snapshots. If the database changes between calling Collection.find and fetching the results of the cursor, or while fetching results from the cursor, those changes may or may not appear in the result set.
Cursors are a reactive data source. The first time you retrieve a cursor's documents with fetch, map, or forEach inside a reactive computation (eg, a template or autorun), Meteor will register a dependency on the underlying data. Any change to the collection that changes the documents in a cursor will trigger a recomputation. To disable this behavior, pass {reactive: false} as an option to find.
The reactivity of cursors is important. If I have a cursor object, I can retrieve the current set of documents it represents by calling fetch() on it. If the data changes in between calls, the fetch() method will actually return a different array of documents. Many things in Meteor natively understand the reactivity of cursors. This is why we can return a cursor object from a template helper function:
Template.foo.documents = function() {
return MyCollection.find(); // returns a cursor object, rather than an array of documents
};
Behind the scenes, Meteor's templating system knows to call fetch() on this cursor object. When the server sends the client updates telling it that the collection has changed, the cursor is informed of this change, which causes the template helper to be recomputed, which causes the template to be rerendered.

A Meteor.Collection is an object that you would define like this:
var collection = new Meteor.Collection("collection");
This object then lets you store data in your mongo database. Note just defining a collection this way does not create a collection in your mongo database. The colleciton would be created after you insert a document in.
So in this way you would not have a collection called name until you insert a document to it.
A cursor is the result of a .find() operation:
var cursor = collection.find()
You may have 1000s of documents, the cursor lets you go through them, one by one, without having to load all of them into your server's RAM.
You can then loop through using forEach, or use some of the other operations as specified in the docs : http://docs.meteor.com/#meteor_collection_cursor
A Cursor is also a reactive data source on the client, so if data changes, you can use the same query to update your DOM.
As Neil mentions its also worthwhile knowing Mongo is a NoSQL database. This means you don't have to really create tables/collections. You would just define a collecction like above, then insert a document to it. This way the collection would be created if it didn't exist. If it already existed, it would be inserted into that collection instead.
Browsing your local database
You don't really need to concern yourself with MongoDB until you are publishing your app, you can just interact with it using Meteor alone. In case you want to have a look at what it looks like:
If you want to have a look at your Mongo database. While meteor is running, in the same directory use meteor mongo to bring up a mongo shell, or use a tool like robomongo (Gui tool) to connect to localhost on port 3002 to have a peek at what your mongo database looks like.

Related

In MongoDB, is there a way to update many documents and get the documents that were modified in a single call?

I'm working with the Mongo Java Driver, but looking through Mongo's documentation, it doesn't look driver specific.
update(filter, update) can update multiple documents but returns a WriteResult which only provides flags/counts.
findOneAndUpdate(filter, update) returns the actual document that was modified, but it can only update one document at a time.
Is there no way to do this in one call? If not, the client would have to call find(filter), then update(filter, update), then find(...) with a new filter matching the IDs obtained in the initial find (since the update can potentially change document values that were in the initial filter).
Is there a better way?
I am unaware of any write commands that return a cursor, which is essentially what you are asking for, nor am I seeing anything relevant in driver source.

Default options for dynamic MongoDB collections

I am aware that MongoDB will dynamically create a collection when you attempt to insert a document into a non-existent collection. My question is:
How do I set up default options so that the collection has the options I want when it is dynamically created?
I don't think you can do that. Your options are:
Pre-create the collections if the pattern is dynamic yet predictable.
List the existing collections before inserting and create the new collection yourself with the right options if it's not already present.
Do not use dynamic collections but rather put the dynamic part as a property to individual documents in a shared collection.
I chose to write a wrapper around mongoc_database_get_collection(). There is a little bit of additional overhead for an extra round trip request to the mongo server to see if the collection already exists. If not, the wrapper creates it with the options I want and returns the new collection. If the collection already exists, the wrapper returns the existing collection.

Create a document without returning it, in MongoDB / mongoose

I am creating a lot of documents, and I am concerned that half of the server bandwidth is being spent on returning those new documents back to the caller.
I don't want the server to return the document to me. I just want to get an acknowledgement once the document has been saved.
I have been able to address this concern when updating a document, by using Model.updateOne() instead of Model.findOneAndUpdate().
But how can I do the same when creating a document?
So far I have tried:
Model.create(docData)
new Model(docData).save()
Model.collection.insert(docData)
Model.collection.insertMany([docData])
but in every case, mongoose (or the mongodb driver) returns a document to me.
I am not sure if MongoDB is actually sending the document back over the network, or if it is just sending back the new _id and that is being appended to the original data by the driver. But I fear the former.
How can I save the document without MongoDB sending it back to me?
According to mongoose document of insertMany it says that the result is an insertWriteOpCallback which, according to the documentation of mongodb driver says that it return the inserted documents.
In other hands the mongodb documentation about insert tells us about a WriteResult object that is not returning any document.
The answer is that mongodb-driver is adding the inserted document into it's response.
What you can do is to use the method bulkWrite from mongodb-native driver, which allow you to perform an insert and get the mongodb response only (so without documents).

Copy data field from one mongo collection to another, on db server

I have two mongo collections. One we can call a template and second is instance. Every time new instance is created, rather large data field is copied from template to instance. Currently the field is retrieved from mongo db template collection in application and then sent back to db as a part of instance collection insert.
Would it be possible to somehow perform this copy on insert directly in mongo db, to avoid sending several megabytes over the network back and forth?
Kadira is reporting 3 seconds lag due to this. And documents are only going to get bigger.
I am using Meteor, but I gather that that should not influence the answer much.
I have done some searching and I can't really find an elegant solution for you. The two ways I can think of doing it are:
1.) Fork a process to run a mongo command to copy your template as your new instance via db.collection.copyTo().
http://eureka.ykyuen.info/2015/02/26/meteor-run-shell-command-at-server-side/
https://docs.mongodb.org/manual/reference/method/db.collection.copyTo/
Or
2.) Attempt to access the raw mongo collection rather than the minimongo collection meteor provides you with so you can use the db.collection.copyTo() functionality supplied by Mongo.
var rawCollection = Collection.rawCollection();
rawCollection.copyTo(newCollection);
Can meteor mongo driver handle $each and $position operators?
I haven't tried accessing the rawCollection to see if copyTo is available, and I also don't know if it will bring it into meteor before writing out the new collection. I'm just throwing this out here as an idea for you; hopefully someone else has a better one.

Atomicity of Model.create in Mongoose when passing an array of documents

So I understand that MongoDB (and by proxy Mongoose) does not support transactions, but that operations involving a single document are always atomic. In looking over the Mongoose docs, I ran into Model.create which allows one to pass an array of documents and store them in a single action, like so:
var array = [{ type: 'jelly bean' }, { type: 'snickers' }];
Candy.create(array, function (err, jellybean, snickers) {
// ...
}
Is this action atomic? Does Mongo save all the documents at once, or does the Mongoose ODM loop through the array, saving one document at a time? Sources (or source code) would be greatly appreciated. (Also, I'm new, so please, don't shoot!)
MongoDB Wire Protocol accepts either single document or multiple documents with OP_INSERT. However, on the server they are still inserted one at a time.
In other words, if the server were to crash part-way through the insert, some documents would be inserted and others would not be. Within each document you are guaranteed consistent view of it - either it's all inserted or it's not. But for multiple documents no such guarantee exists.