在MongoDB中使用$ addtoset添加元素到数组

我正在尝试使用addtoset更新集合内的数组的示例。 新的元素正在被添加,但并非如预期的那样。 根据addtoset,只有当它不在列表中时,才会添加一个新的元素。

问题:

它只是采取任何元素被添加。

这是我的代码示例

架构(mongo_database.js):

var category = new Schema({ Category_Name: { type: String, required: true}, //SubCategories: [{}] Category_Type: { type: String}, Sub_Categories: [{Sub_Category_Name: String, UpdatedOn: { type:Date, default:Date.now} }], CreatedDate: { type:Date, default: Date.now}, UpdatedOn: {type: Date, default: Date.now} }); 

service.js

 exports.addCategory = function (req, res){ //console.log(req.body); var category_name = req.body.category_name; var parent_category_id = req.body.parent_categoryId; console.log(parent_category_id); var cats = JSON.parse('{ "Sub_Category_Name":"'+category_name+'"}'); //console.log(cats); var update = db.category.update( { _id: parent_category_id }, { $addToSet: { Sub_Categories: cats} }, { upsert:true } ); update.exec(function(err, updation){ }) } 

有人能帮我弄清楚这个吗?

非常感谢..

正如前面提到的那样, $addToSet不能以这种方式工作,因为数组中的元素或“set”是为了真正表示每个元素完全唯一的“set”。 此外,诸如.update()类的操作方法不考虑mongoose模式默认或validation规则。

然而,像.update()这样的操作比“查找”文档更有效,然后操作和使用.save()来更改客户端代码。 它们还避免了其他进程或事件操作在检索到文档后可能修改文档的并发性问题。

要做你想做的事情,需要向服务器发送“多”更新语句。 我不是一个“后备”逻辑情况,当一个操作不更新文件时,你回退到下一个:

models / category.js

 var mongoose = require('mongoose'), Schema = mongoose.Schema; var category = new Schema({ Category_Name: { type: String, required: true}, Category_Type: { type: String}, Sub_Categories: [{Sub_Category_Name: String, UpdatedOn: { type:Date, default:Date.now} }], CreatedDate: { type:Date, default: Date.now}, UpdatedOn: {type: Date, default: Date.now} }); exports.Category = mongoose.model( "Category", category ); 

在你的代码中

 var Category = require('models/category').Category; exports.addCategory = function(req,res) { var category_name = req.body.category_name; var parent_category_id = req.body.parent_categoryId; Category.update( { "_id": parent_category_id, "Sub_Categories.Sub_Category_Name": category_name }, { "$set": { "Sub_Categories.$.UpdatedOn": new Date() } }, function(err,numAffected) { if (err) throw error; // or handle if ( numAffected == 0 ) Category.update( { "_id": parent_category_id, "Sub_Categories.Sub_Category_Name": { "$ne": category_name } }, { "$push": { "Sub_Categories": { "Sub_Category_Name": category_name, "UpdatedOn": new Date() } } }, function(err,numAffected) { if (err) throw err; // or handle if ( numAffected == 0 ) Category.update( { "_id": parent_category_id }, { "$push": { "Sub_Categories": { "Sub_Category_Name": category_name, "UpdatedOn": new Date() } } }, { "$upsert": true }, function(err,numAffected) { if (err) throw err; } ); }); ); } ); }; 

基本上可以尝试三种操作:

  1. 尝试匹配存在类别名称的文档,并更改匹配的数组元素的“UpdatedOn”值。

  2. 如果没有更新。 查找与parentId匹配的文档,但是数组中不存在类别名称并推送一个新元素。

  3. 如果没有更新。 执行一个试图匹配parentId的操作,只需要将upsert设置为true的数组元素。 由于以前的更新都失败了,这基本上是一个插入。

你可以通过使用诸如async.waterfall之类的东西来传递numAffected值并避免缩进蠕变,或者根据我个人的喜好,不打扰检查受影响的值,只是一次通过批量操作API 。

后者可以通过如下的mongoose模型访问:

 var ObjectId = mongoose.mongo.ObjectID, Category = require('models/category').Category; exports.addCategory = function(req,res) { var category_name = req.body.category_name; var parent_category_id = req.body.parent_categoryId; var bulk = Category.collection.initializeOrderBulkOp(); // Reversed insert bulk.find({ "_id": { "$ne": new ObjectId( parent_category_id ) }) .upsert().updateOne({ "$setOnInsert": { "_id": new ObjectId( parent_category_id ) }, "$push": { "Sub_Category_Name": category_name, "UpdatedOn": new Date() } }); // In place bulk.find({ "_id": new ObjectId( parent_category_id ), "Sub_Categories.Sub_Category_Name": category_name }).updateOne({ "$set": { "Sub_Categories.$.UpdatedOn": new Date() } }); // Push where not matched bulk.find({ "_id": new ObjectId( parent_category_id ), "Sub_Categories.Sub_Category_Name": { "$ne": category_name } }).updateOne({ "$push": { "Sub_Category_Name": category_name, "UpdatedOn": new Date() } }); // Send to server bulk.execute(function(err,response) { if (err) throw err; // or handle console.log( JSON.stringify( response, undefined, 4 ) ); }); }; 

注意“upsert”首先出现的颠倒的逻辑,但是如果成功则只有“second”声明适用,但实际上在Bulk API下不会影响文档。 您将得到一个WriteResult对象,其基本信息与此类似(缩略forms):

 { "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 } 

或者在“upsert”上:

 { "nMatched" : 1, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("54af8fe7628bee196ce97ce0") } 

还要注意,需要包含来自基本mongo驱动程序的ObjectId函数,因为这是来自基本驱动程序的“原始”方法,并不像mongoose方法那样基于模式“自动生成”。

此外,要非常小心,因为它是一个基本的驱动程序方法,并不共享mongoose的逻辑,所以如果没有连接build立到数据库已经然后调用.collection访问器将不会返回一个Collection对象和后续的方法调用失败。 mongoose本身做了一个懒惰的数据库连接,并且方法调用被“排队”,直到连接可用。 基本的驱动程序方法并非如此。

所以可以这样做,只是需要处理这种数组处理的逻辑,因为没有本地操作符来处理。 但是,如果你采取适当的照顾,它仍然非常简单,非常有效。