我一直在使用本机MongoDB驱动程序在Node.JS中构建应用程序 - 它包含联系人,当用户接受联系人时,它应该从“待处理”和“已发送”联系人中删除,然后添加到“联系人” ”
示例代码和文档:
/*
=============================
User "john"
=============================
{
username: "john",
contacts: ["jim"],
pending_contacts: ["bob"]
}
=============================
User "bob"
=============================
{
username: "bob",
contacts: ["dave"],
sent_contacts: ["john"]
}
=============================
What SHOULD happen
=============================
{
username: "bob",
contacts: ["dave", "john"],
sent_contacts: []
},
{
username: "john",
contacts: ["jim", "bob"],
pending_contacts: []
}
=============================
What ACTUALLY 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 who = [contact, username];
var finishCount = 0;
// finish will 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 an error
function failed(err) {
callback(err, null)
}
console.log('removing %s and %s from pending and sent', username, contact)
col.update(
{username: { $in: who }},
{
$pullAll: {
sent_contacts: who,
pending_contacts: who
}
}, {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');
}
);
第一次更新会从每个其他待处理/已发送列表中删除联系人和所有者,第二次和第三次更新会将所有者添加到联系人的联系人列表中,反之亦然。
问题是,最终结果看起来好像删除从未发生过,尽管删除查询本身完全正常。我不知道这是MongoDB本身的问题(或者如果它是有意的),或者如果它是驱动程序的问题,所以我希望有人至少可以为我澄清这一点。
注意:是的我知道它们是异步运行的。通过将每个更新放在上一个回调中,一个接一个地运行它们并没有什么不同。在有人抱怨这段代码看起来有多糟糕之前,我之前已经在Async.JS中设置了它,但是我从这个代码示例中删除了它,以确保Asyn.cJS不对这些问题负责。
答案 0 :(得分:1)
使用节点本机驱动程序,每次都适用于我:
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);
},
// Do updates
function(callback) {
// Init batch
var bulk = coll.initializeOrderedBulkOp();
// Add to user and pull from pending
bulk.find({
"username": user,
"contacts": { "$ne": contact },
}).updateOne({
"$push": { "contacts": contact },
"$pull": { "pending_contacts": contact }
});
// Add to contact and pull from 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();
}
);
});
输出:
{ 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: [] } ]
这里的改进基本上是使用Bulk Operations API并立即将所有更新发送到服务器并获得单个响应。另请注意在更新和查询选择中使用运算符。
简单地说,你已经知道&#34;用户&#34;以及&#34;联系&#34;他们正在接受。接受的联系是&#34;待定&#34;并且联系人自己让用户进入&#34;发送&#34;。
这些实际上只是对任一阵列的简单$push
和$pull
操作。查询条件不是在此处使用$addToSet
,而是确保在执行更新时存在期望值。这也保留了&#34; order&#34; $addToSet
基本上无法保证,因为它是&#34; set&#34;,这是无序的。
一个发送到服务器和一个回调响应,让两个用户都正确更新。更有意义的是发送多个更新并等待每个更新的回调响应。
无论如何,这是一个完整的自包含列表,只有两个命名的依赖项,因此您可以自己轻松运行并确认结果。
当我说&#34;完成并且自包含&#34;它意味着启动一个新项目并简单地运行代码。这是完整的说明:
mkdir sample
cd sample
npm init
npm install mongodb --save
npm install async --save
然后使用该文件夹中的代码列表创建一个文件,例如test.js
,然后运行:
node test.js