Mongoose:无法使用$ addToSet或$ push将新对象添加/推送到数组

我使用Nodejs,Hapijs和Mongoose。

我有一个模式和模型如下。

var schema = { name: { type: String, required: true }, lectures: {} }; var mongooseSchema = new mongoose.Schema(schema, { collection: "Users" }); mongoose.model("Users", mongooseSchema); 

出于某种原因,我需要保持“讲座”混合型。

在保存/创build文档时,我创build了一个嵌套的属性lectures.physics.topic [] ,其中topic是一个数组。

现在,我试图使用$ addToSet或$ push将新对象添加到“lectures.physics.topic”。

 userModel.findByIdAndUpdateAsync(user._id, { $addToSet: { "lectures.physics.topic": { "name": "Fluid Mechanics", "day": "Monday", "faculty": "Nancy Wagner" } } }); 

但是文件根本没有得到更新。 我也试过使用$ push。 没有工作。 可能是什么问题呢?

我尝试了另一种方法,使用mongoclient,直接更新数据库。它的工作原理请find下面的代码工作

 db.collection("Users").update({ "_id": user._id }, { $addToSet: { "lectures.physics.topic": { "name": "Fluid Mechanics", "day": "Monday", "faculty": "Nancy Wagner" } } }, function(err, result) { if (err) { console.log("Superman!"); console.log(err); return; } console.log(result); }); 

每次请求被打时,我都必须启动mongo客户端。这不是一个可行的解决scheme。

我会打电话给这个“bug”。 mongoose显然是做了错误的事情,在日志中可以certificate,如后面所示。 但是,这里是一个列表,它调用本地驱动程序中的.findOneAndUpdate() ,它与您尝试执行的更新相同:

 var async = require('async'), mongoose = require('mongoose'), Schema = mongoose.Schema; mongoose.connect('mongodb://localhost/school'); mongoose.set('debug',true); var userSchema = new Schema({ name: { type: String, required: true }, lectures: { type: Schema.Types.Mixed } }); var User = mongoose.model( "User", userSchema ); function logger(data) { return JSON.stringify(data, undefined, 2); } async.waterfall( [ function(callback) { User.remove({},function(err) { callback(err); }); }, function(callback) { console.log("here"); var user = new User({ "name": "bob" }); user.save(function(err,user) { callback(err,user); }); }, function(user,callback) { console.log("Saved: %s", logger(user)); User.collection.findOneAndUpdate( { "_id": user._id }, { "$addToSet": { "lectures.physics.topic": { "name": "Fluid Mechanics", "day": "Monday", "faculty": "Nancy Wagner" } } }, { "returnOriginal": false }, function(err,user) { callback(err,user); } ); } ], function(err,user) { if (err) throw err; console.log("Modified: %s", logger(user)); mongoose.disconnect(); } ); 

这与结果完美结合:

 Saved: { "__v": 0, "name": "bob", "_id": "55cda1f5b5ee8b870e2f53bd" } Modified: { "lastErrorObject": { "updatedExisting": true, "n": 1 }, "value": { "_id": "55cda1f5b5ee8b870e2f53bd", "name": "bob", "__v": 0, "lectures": { "physics": { "topic": [ { "name": "Fluid Mechanics", "day": "Monday", "faculty": "Nancy Wagner" } ] } } }, "ok": 1 } 

你需要小心,因为原生的驱动程序方法不知道像mongoose方法的连接状态。 所以你需要确保一个“mongoose”方法发起连接,或者在连接事件中包装你的应用程序,如下所示:

 mongoose.connection.on("connect",function(err) { // start app in here }); 

至于“bug”,请看这个清单的日志输出:

 var async = require('async'), mongoose = require('mongoose'), Schema = mongoose.Schema; mongoose.connect('mongodb://localhost/school'); mongoose.set('debug',true); var userSchema = new Schema({ name: { type: String, required: true }, lectures: { type: Schema.Types.Mixed } }); var User = mongoose.model( "User", userSchema ); function logger(data) { return JSON.stringify(data, undefined, 2); } async.waterfall( [ function(callback) { User.remove({},function(err) { callback(err); }); }, function(callback) { console.log("here"); var user = new User({ "name": "bob" }); user.save(function(err,user) { callback(err,user); }); }, function(user,callback) { console.log("Saved: %s", logger(user)); User.findByIdAndUpdate( user._id, { "$addToSet": { "lectures.physics.topic": { "name": "Fluid Mechanics", "day": "Monday", "faculty": "Nancy Wagner" } } }, { "new": true }, function(err,user) { callback(err,user); } ); } ], function(err,user) { if (err) throw err; console.log("Modified: %s", logger(user)); mongoose.disconnect(); } ); 

和mongoose日志logging的日志输出:

 Mongoose: users.remove({}) {} here Mongoose: users.insert({ name: 'bob', _id: ObjectId("55cda2d2462283c90ea3f1ad"), __v: 0 }) Saved: { "__v": 0, "name": "bob", "_id": "55cda2d2462283c90ea3f1ad" } Mongoose: users.findOne({ _id: ObjectId("55cda2d2462283c90ea3f1ad") }) { new: true, fields: undefined } Modified: { "_id": "55cda2d2462283c90ea3f1ad", "name": "bob", "__v": 0 } 

所以在真正的“忽悠?” 风格,那里有一个调用.findOne() ? 这不是被问到的。 而且,当然数据库中没有任何变化,因为错误的调用。 所以即使是{ "new": true }也是多余的。

这发生在所有级别的“混合”模式types。

就我个人而言,我不会像这样嵌套在“对象”中,只是将标准数组的“对象键”部分作为附加属性。 MongoDB和mongoose都非常高兴,而且用这种结构查询信息要容易得多。

 var async = require('async'), mongoose = require('mongoose'), Schema = mongoose.Schema; mongoose.connect('mongodb://localhost/school'); mongoose.set('debug',true); var lectureSchema = new Schema({ "subject": String, "topic": String, "day": String, "faculty": String }); var userSchema = new Schema({ name: { type: String, required: true }, lectures: [lectureSchema] }); var User = mongoose.model( "User", userSchema ); function logger(data) { return JSON.stringify(data, undefined, 2); } async.waterfall( [ function(callback) { User.remove({},function(err) { callback(err); }); }, function(callback) { console.log("here"); var user = new User({ "name": "bob" }); user.save(function(err,user) { callback(err,user); }); }, function(user,callback) { console.log("Saved: %s", logger(user)); User.findByIdAndUpdate( user._id, { "$addToSet": { "lectures": { "subject": "physics", "topic": "Fluid Mechanics", "day": "Monday", "faculty": "Nancy Wagner" } } }, { "new": true }, function(err,user) { callback(err,user); } ); } ], function(err,user) { if (err) throw err; console.log("Modified: %s", logger(user)); mongoose.disconnect(); } ); 

输出:

 Mongoose: users.remove({}) {} here Mongoose: users.insert({ name: 'bob', _id: ObjectId("55cda4dc40f2a8fb0e5cdf8b"), lectures: [], __v: 0 }) Saved: { "__v": 0, "name": "bob", "_id": "55cda4dc40f2a8fb0e5cdf8b", "lectures": [] } Mongoose: users.findAndModify({ _id: ObjectId("55cda4dc40f2a8fb0e5cdf8b") }) [] { '$addToSet': { lectures: { faculty: 'Nancy Wagner', day: 'Monday', topic: 'Fluid Mechanics', subject: 'physics', _id: ObjectId("55cda4dc40f2a8fb0e5cdf8c") } } } { new: true, upsert: false, remove: false } Modified: { "_id": "55cda4dc40f2a8fb0e5cdf8b", "name": "bob", "__v": 0, "lectures": [ { "faculty": "Nancy Wagner", "day": "Monday", "topic": "Fluid Mechanics", "subject": "physics", "_id": "55cda4dc40f2a8fb0e5cdf8c" } ] } 

所以工作正常,你不需要挖掘本地方法,只是为了使其工作。

数组的属性使得查询和过滤变得容易,并且跨数据“聚合”信息,对于所有这些MongoDB来说,它们都喜欢“严格path”来引用所有信息。 否则,你只能看到“特定的键”,而不能提及每一个可能的“键组合”的索引或真正的search。

像这样的属性是更好的方法去。 没有错误在这里。

Mongoose失去了自动检测和保存对混合types所做更改的function,因此您需要通过调用文档的.markModified(path)方法来将“Mixed”types的值传递给“混合”types你只是改变了:

 doc.mixed.type = 'changed'; doc.markModified('mixed.type'); doc.save() // changes to mixed.type are now persisted 

在你的情况下,可以使用findById()方法通过调用主题数组上的findById()方法来进行更改,然后触发save()方法来save()更改:

 userModel.findById(user._id, function (err, doc){ var item = { "name": "Fluid Mechanics", "day": "Monday", "faculty": "Nancy Wagner" }; doc.lectures.physics.topic.addToSet(item); doc.markModified('lectures'); doc.save() // changes to lectures are now persisted });