node.js - Why is MongoDB ignoring some of my updates? -
i've been building application in node.js using native mongodb driver - includes contacts, , when user accepts contact, should remove "pending" , "sent" contacts, add "contacts".
example code , documents:
/* ============================= user "john" ============================= { username: "john", contacts: ["jim"], pending_contacts: ["bob"] } ============================= user "bob" ============================= { username: "bob", contacts: ["dave"], sent_contacts: ["john"] } ============================= should happen ============================= { username: "bob", contacts: ["dave", "john"], sent_contacts: [] }, { username: "john", contacts: ["jim", "bob"], pending_contacts: [] } ============================= happens ============================= { username: "john", contacts: ["jim", "bob"], pending_contacts: ["bob"] }, { username: "bob", contacts: ["dave", "john"], sent_contacts: ["john"] } */ var col = this.db.collection('users'); var contact = "bob", username = "john"; var = [contact, username]; var finishcount = 0; // finish run 3 times before callback function finish(name) { console.log(name, ' has finished'); finishcount++; if(finishcount<3) return; callback(false, null); } // run if there's error function failed(err) { callback(err, null) } console.log('removing %s , %s pending , sent', username, contact) col.update( {username: { $in: }}, { $pullall: { sent_contacts: who, pending_contacts: } }, {multi: 1}, function(err,data) { if(err) return failed(err); finish('remove_contacts'); } ); col.update( {username: username}, {$addtoset: {contacts: contact}}, function(err,res) { if(err) return failed(err); console.log('added 1'); finish('add_to_user'); } ); col.update( {username: contact}, {$addtoset: {contacts: username}}, function(err,res) { if(err) return failed(err); console.log('added 2'); finish('add_to_contact'); } );
the first update removes contact , owner each-others pending/sent list, second , third update add owner contact's contact list , vice versa.
the issue is, final result appears if removal never happened, though removal query works fine itself. don't know if problem mongodb (or if it's intended), or if it's issue driver, hope can @ least clarify me.
note: yes know run asynchronously. running them 1 after other putting each update in previous callback not make difference. before complains how awful code looks, had set within async.js removed code sample ensure asyn.cjs not responsible issues.
using node native driver works me every time:
var mongodb = require('mongodb'), async = require('async'), mongoclient = mongodb.mongoclient; var user = "john", contact = "bob"; var contactslist = [ { "username": "john", "contacts": [ "jim" ], "pending_contacts": [ "bob" ] }, { "username": "bob", "contacts": [ "dave" ], "sent_contacts": [ "john" ] } ]; mongoclient.connect('mongodb://localhost/test',function(err,db) { var coll = db.collection("contacts"); async.series( [ // wipe clean function(callback) { coll.remove({},callback) }, // init collection function(callback) { async.each(contactslist,function(contact,callback) { coll.insert(contact,callback); },callback); }, // updates function(callback) { // init batch var bulk = coll.initializeorderedbulkop(); // add user , pull pending bulk.find({ "username": user, "contacts": { "$ne": contact }, }).updateone({ "$push": { "contacts": contact }, "$pull": { "pending_contacts": contact } }); // add contact , pull sent bulk.find({ "username": contact, "contacts": { "$ne": user }, "sent_contacts": user }).updateone({ "$push": { "contacts": user }, "$pull": { "sent_contacts": user } }); // execute bulk.execute(function(err,response) { console.log( response.tojson() ); callback(err); }); }, // list collection function(callback) { coll.find({}).toarray(function(err,results) { console.log(results); callback(err); }); } ], function(err) { if (err) throw err; db.close(); } ); });
and output:
{ ok: 1, writeerrors: [], writeconcernerrors: [], insertedids: [], ninserted: 0, nupserted: 0, nmatched: 2, nmodified: 2, nremoved: 0, upserted: [] } [ { _id: 55b0c16934fadce812cdcf9d, username: 'john', contacts: [ 'jim', 'bob' ], pending_contacts: [] }, { _id: 55b0c16934fadce812cdcf9e, username: 'bob', contacts: [ 'dave', 'john' ], sent_contacts: [] } ]
improvements here use bulk operations api , send updates @ once server , single response. note use of operators in updates , query selection well.
simply put, know "user" "contact" accepting. contact accepted "pending" , contact have user in "sent".
these simple $push
, $pull
operations on either array appropriate. rather using $addtoset
here, query conditions make sure expected values present when performing update. preserves "order" $addtoset
can not guarantee, because it's "set", un-ordered.
one send server , 1 callback response, leaving both users updated correctly. makes more sense sending multiple updates , waiting callback response each.
anyhow, complete self contained listing 2 named dependencies, can run , confirm results.
when "complete , self contained" means start new project , run code. here's complete instruction:
mkdir sample cd sample npm init npm install mongodb --save npm install async --save
then create file code listing in folder, test.js
, run:
node test.js
Comments
Post a Comment