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 });