Mongo更新没有按预期工作

假设我有这个模型:

var stuffSchema = new mongoose.Schema({ "id": 1, "cars": { "suv": [], "sports": [], "supercar": [{ "owner": "nick", "previousOwners": [ ObjectId("574e1bc0abfb4a180404b17f"), ObjectId("574e1bdeabfb4a180404b180"), ObjectId("574e1c4babfb4a180404b181"), ObjectId("574e1c67abfb4a180404b182"), ObjectId("574e23abd25baf340e678b2d"), ObjectId("574e241ec8caa3a81cc85ed5") ] }] } }); var Stuff = mongoose.model('Stuff', stuffSchema); 

如果特定owner已经存在,我想添加一个previousOwnersowner ,并且如果特定owner不存在,则添加一个新的owner及其各自的previousOwnerowner

这是我的尝试:

 Stuff.update({ id: 1, 'cars.supercar.owner': 'olix' }, { $addToSet: { 'cars.supercar.$.previousOwners': ObjectId("574e241ec8caa3a81c893e73") } }, { $upsert: true }, function(err) { if (err) { console.log('Error: ' + err); } }); 

我期望这个将添加一个新的owner称为'olix'伴随其previousOwners数组。 这将使我的文件看起来像这样:

 { "id": 1, "cars": { "suv": [], "sports": [], "supercar": [{ "owner": "nick", "previousOwners": [ ObjectId("574e1bc0abfb4a180404b17f"), ObjectId("574e1bdeabfb4a180404b180"), ObjectId("574e1c4babfb4a180404b181"), ObjectId("574e1c67abfb4a180404b182"), ObjectId("574e23abd25baf340e678b2d"), ObjectId("574e241ec8caa3a81cc85ed5") ], "owner": "olix", "previousOwners": [ ObjectId("574e241ec8caa3a81c893e73") ] }] } } 

它根本不工作。 这甚至不会产生错误。 我试过了:

 db.stuffs.find({id: 1, 'cars.supercar.owner': 'nick'}) 

并成功返回文档。 只是为了确保我的查询是正确的。

我究竟做错了什么?

首先你的模式定义是不正确的,用它来代替:

 var stuffSchema = new mongoose.Schema({ 'id': Number, 'cars': { 'suv': [], 'sports': [], 'supercar': [{ _id: false, 'owner': { type: String }, 'previousOwners': [{ type: mongoose.Schema.ObjectId }] }] } }); var Stuff = mongoose.model('Stuff', stuffSchema); 

将更新查询更改为:

 Stuff.update({ id: 1 }, { $addToSet: { 'cars.supercar': { 'owner': 'olix', 'previousOwners': [ObjectId('574e241ec8caa3a81c893e75')] } } }, function(err) { if (err) { console.log('Error: ' + err); } }); 

注意:mongoose会检查对象的每个属性,所以supercar数组对象是一样的,如果它的owner字段和previousOwners数组完全相同,否则它会将新对象推入supercar数组中。

我通过手动更新来解决它:

 Stuff.findOne({ id: 1 }, function(err, stuff) { if (err) { return done(err); } var ownersList = stuff.cars.supercar.map(function(supercarCar) { return supercarCar.owner; }); var ownerIndex = ownersList.indexOf('nick'); if (ownerIndex != -1) { stuff.cars.supercar[ownerIndex].previousOwners.push(ObjectId("574e241ec8caa3a81c893e73")); } else { stuff.cars.supercar.push({ owner: 'nick', previousOwners: [ObjectId("574e241ec8caa3a81c893e73")] }) } stuff.save(function(err) { if (err) { return done(err); } }); }); 

笔记
这是一个伪造的文件,所有的财产名称已被匿名更改。
done函数在这里被使用,因为这个代码被运行在一个.pre(模式的'save'实例中。
仅仅为了举例的目的,一些值是硬编码的。