saving and updating

29 views
Skip to first unread message

Rick

unread,
Aug 4, 2010, 4:49:07 PM8/4/10
to node-mongodb-native
Hi guys,

Has anybody had problems using *save*?

Until today I have been using insert, however I needed to update a
document for the first time...

So I switched to using save i.e.

collection.save(doc, function(err, res) {

})

If I create a document and call save (on the collection) all is well.

However if I load the same document from mongo.. then modify the
document and try to persist these changes using *save* - these changes
do not persist. The callback does fire (with no error).

Any ideas?

nwhite

unread,
Aug 4, 2010, 5:01:22 PM8/4/10
to node-mong...@googlegroups.com
just out of curiosity, did you check to see if the document was inserted with a different ObjectID?

I'm also assuming your using the latest and greatest version?

Are you doing anything fancy to your document before save?

rick....@gmail.com

unread,
Aug 5, 2010, 4:00:36 AM8/5/10
to node-mong...@googlegroups.com
Yeah - I checked the collection and no additional data is added or updated.....

I dont think I'm doing anything out of the ordinary - a simple find and then a save :(

christkv

unread,
Aug 5, 2010, 4:40:59 AM8/5/10
to node-mongodb-native
An example of the code would be helpful as well as an example of the
object you are trying
to save after modification.

Remember the object has to be a pure json object, no functions are
allowed. also needs to contain a _id field that is an instance of
ObjectID.

Cheers

On Aug 5, 10:00 am, rick.wa...@gmail.com wrote:
> Yeah - I checked the collection and no additional data is added or
> updated.....
>
> I dont think I'm doing anything out of the ordinary - a simple find and then
> a save :(
>
>
>
> On Wed, Aug 4, 2010 at 10:01 PM, nwhite <changereal...@gmail.com> wrote:
> > just out of curiosity, did you check to see if the document was inserted
> > with a different ObjectID?
>
> > I'm also assuming your using the latest and greatest version?
>
> > Are you doing anything fancy to your document before save?
>

rick....@gmail.com

unread,
Aug 5, 2010, 5:42:26 AM8/5/10
to node-mong...@googlegroups.com
Ok....

So in the database I have:

{"n":"me","created_at":"2010-08-05T08:49:44.135Z","_id":"4c5a7b28d7e1612108000001"}

After I execute the code (node app.js) I see:

found!

{"n":"me","created_at":"2010-08-05T08:49:44.135Z","_id":"4c5a7b28d7e1612108000001"}

saved...

Next I look in the database and see that the data is unchanged :(

Here is the code:

So I have a helper class called DataProvider: The code for this is here: http://pastie.org/1077010

I construct an instance of this:

var myCollection  = new DataProvider(host,port,"core", "collection");

myCollection.findById("4c5a7b28d7e1612108000001", function(error, result){

if(error) {
require('sys').debug("error!");
} else if (result) {

                require('sys').debug("found!");

                require('sys').debug(JSON.stringify(result));
result.newField="data";
myCollection.save(result,function(error,result) {

         
});
      }
})

christkv

unread,
Aug 5, 2010, 5:55:39 AM8/5/10
to node-mongodb-native
Hi

Ok so the code for the save function looks like this

Collection.prototype.save = function(doc, options, callback) {
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : null;

var id = (doc instanceof OrderedHash) ? doc.get('_id') : doc['_id'];

if(id != null) {
this.update({'_id':id}, doc, {upsert: true, safe: options !=
null ? options.safe : false}, callback);
} else {
this.insert(doc, function(err, docs) { Array.isArray(docs) ?
callback(err, docs[0]) : callback(err, docs); });
}
};

as you see it's an update call for the save only if the _id attribute
exists on the document which it does on yours. However if it's not a
ObjectID instance it won't work as the bson serializer will fail.

So do something like this

var ObjectID = require('mongodb').ObjectID,
sys = require('sys');

sys.puts("====================== " + (yourdoc._id instanceof
ObjectID));

it should be true for it to work.
Are you doing a toJson on the original doc changing it and then saving
it using save ?
in that case you have to ensure that you create a ObjectID object
around the _id hex value as
toJson converts the ObjectID object to a hex representation.

yourdoc._id = new ObjectID(yourdoc._id)

Cheers

Christian

On Aug 5, 11:42 am, rick.wa...@gmail.com wrote:
> Ok....
>
> So in the database I have:
>
> {"n":"me","created_at":"2010-08-05T08:49:44.135Z","_id":"4c5a7b28d7e1612108 000001"}
>
> After I execute the code (node app.js) I see:
>
> found!
>
> {"n":"me","created_at":"2010-08-05T08:49:44.135Z","_id":"4c5a7b28d7e1612108 000001"}
>
> saved...
>
> Next I look in the database and see that the data is unchanged :(
>
> Here is the code:
>
> So I have a helper class called DataProvider: The code for this is here:http://pastie.org/1077010
>
> I construct an instance of this:
>
> var myCollection  = new DataProvider(host,port,"core", "collection");
>
> myCollection.findById("4c5a7b28d7e1612108000001", function(error, result){
>
> if(error) {
> require('sys').debug("error!");
>  } else if (result) {
>
>                 require('sys').debug("found!");
>
>                 require('sys').debug(JSON.stringify(result));
>  result.newField="data";
>  myCollection.save(result,function(error,result) {
>
>  });
>       }
>
>
>
> })

rick....@gmail.com

unread,
Aug 5, 2010, 6:05:21 AM8/5/10
to node-mong...@googlegroups.com
Cheers for the response...

I changed my save method to the following:

save: function(events, callback) {
this.getCollection(function(error, collection) {
if( error ) callback(error)
else {
var returnArray = true;
if( typeof(events.length)=="undefined") {
returnArray = false;
events = [events];
}
for( var i =0;i< events.length;i++ ) {
sys.puts("====================== " + (events[i]._id instanceof ObjectID));
events[i].created_at = new Date();
}
collection.save(events, function(error, results) {
if(error) {
callback(error,null);
} else {
require('sys').debug("saved...");
var result = returnArray ? events : events[0];
callback(null, result);
}
});
}
});
}

when its called the debug out put is:

==================== true

saved!


So it looks like it is a valid ObjectID!

christkv

unread,
Aug 5, 2010, 6:11:44 AM8/5/10
to node-mongodb-native
So one of the core things to understand about mongodb is that all
inserts, updates, deletes are async (fire and forget). Thus you'll
never get an error unless it's a serialization error (which in the
case of _id being a string won't trigger an error).

To check for an insert error you need to call

db.lastError(function(err, err_documents)) {
}

or set the initial db to strict mode.

var error_client = new mongo.Db('integration_tests_', new
mongo.Server("127.0.0.1", 27017, {auto_reconnect: false}),
{strict:true});
test.equal(true, error_client.strict);
error_client.open(function(err, error_client) {
error_client.collection('does-not-exist', function(err,
collection) {
test.ok(err instanceof Error);
test.equal("Collection does-not-exist does not exist.
Currently in strict mode.", err.message);
});

error_client.createCollection('test_strict_access_collection',
function(err, collection) {
error_client.collection('test_strict_access_collection',
function(err, collection) {
test.ok(collection instanceof Collection);
// Let's close the db

finished_test({test_strict_access_collection:'ok'});
error_client.close();
});
});
});

BUT that comes with the cost of two calls pr insert update etc.

Hope it helps with the mental model of how mongodb works.

Cheers and good luck with your app.

Christian

christkv

unread,
Aug 5, 2010, 6:12:56 AM8/5/10
to node-mongodb-native
Ah and check out

http://www.learnboost.com/mongoose/

it's an ODM on top of the mongo driver and takes care of much of the
low level stuff allowing you to focus on the data modeling aspects :)

Christian

rick....@gmail.com

unread,
Aug 5, 2010, 6:16:55 AM8/5/10
to node-mong...@googlegroups.com
Still not sure why this isnt actually working though :(

christkv

unread,
Aug 5, 2010, 6:23:02 AM8/5/10
to node-mongodb-native
Run the driver in strict mode or try calling lastError on the db
object.
Also make sure you are running mongodb 1.4.X as there are some changes
in the 1.5.X branch that
might impact functionality

Cheers

rick....@gmail.com

unread,
Aug 5, 2010, 6:36:43 AM8/5/10
to node-mong...@googlegroups.com
Well - I'm running 1.4.4

In strict mode and also called :

db.lastError(function(err, err_documents){
sys.puts(JSON.stringify(err_documents));
});

after the 'save' which returns [{"err":null,"n":0,"ok":1}]

I tested the database by using the console directly rather than the driver... and I can successfully save....

christkv

unread,
Aug 5, 2010, 6:51:51 AM8/5/10
to node-mongodb-native
Try using the update function directly (make sure you remove the _id
field first)

Cheers

On Aug 5, 12:16 pm, rick.wa...@gmail.com wrote:

rick....@gmail.com

unread,
Aug 5, 2010, 7:27:28 AM8/5/10
to node-mong...@googlegroups.com
Discovered the source of my issue.

In my save method i do the following:

                                       if( typeof(data.length)=="undefined") {
returnArray = false;
data= [data]; //HERE IS THE ISSUE
}
        for( var i =0;i< data.length;i++ ) {
data[i].created_at = new Date();
}

rick....@gmail.com

unread,
Aug 5, 2010, 8:55:17 AM8/5/10
to node-mong...@googlegroups.com
Hi guys - one last question...

*save* supports upserting

*insert* allows for the insertion of mulitple records - from the manual and some tests I've done, mongo db appears to not support updating of  existing records with the *insert* command  - is this correct? (I've been told explicitly otherwise by another developer who is almost always correct)

What is the best approach for updating multiple existing records at once (from a performance pov)?

Cheers for all the help :)

christkv

unread,
Aug 5, 2010, 9:04:42 AM8/5/10
to node-mongodb-native
Ah I missed that, yeah array will not serialize to a valid document :)

Depends

If you are updating several documents with one value then you can
issue on update command and it will update all the documents that
corresponds to the selector.

EX:

collection.update({i:1), {"$set":{"i":500}}, function(err, result) {

will set the field in all document that have i = 1 to i = 500.

If you have multiple distinct documents you have to issue an update
command for each document (meaning that you are using _id to identify
the document). The MongoDB wire protocol in this case only allows you
to pass one document.

So a loop is called for :)

Cheers

rick....@gmail.com

unread,
Aug 5, 2010, 9:09:58 AM8/5/10
to node-mong...@googlegroups.com
Am i correct about the insert statement?

Cheers for your help btw :)

christkv

unread,
Aug 5, 2010, 9:17:34 AM8/5/10
to node-mongodb-native
Yes you are correct insert does not support updating any existing
documents. Updates are fast anyway due to the way Mongo aggressively
keeps data and indexes in memory. I have not noticed any significant
difference between multiple updates and inserts. Since the sockets is
kept open the overhead of sending separate wire messages for each
update vs one wire message for a multiple insert message is small.

You won't have any problems unless you plan for Facebook style
traffic ;)

Have a look at http://github.com/mnutt/hummingbird for a high
performance app

Cheers
Reply all
Reply to author
Forward
0 new messages