使用mongodb中的$ addtoset将元素添加到数组中

时间:2015-01-08 09:38:11

标签: javascript node.js mongodb mongoose mongodb-query

我正在尝试使用 addtoset 更新集合中的数组的示例。新元素正在添加但不是预期的。根据{{​​3}},只有当元素不在列表中时才会添加新元素。

问题:

  

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

这是我的代码示例

架构(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){

            })
    }

有人可以帮我解决这个问题吗?

非常感谢..

1 个答案:

答案 0 :(得分:1)

正如已经提到的那样,$addToSet不能像数组中的元素那样工作,或者" set"意在真正代表" set"每个元素都是独一无二的。此外,.update()等操作方法不会考虑mongoose架构默认或验证规则。

然而,.update()等操作比"发现"更有效。该文档,然后操纵并使用.save()进行客户端代码中的更改。它们还避免了并发问题,其他进程或事件操作可能在检索文档后修改了文档。

做你想做的事情需要制作" mulitple"将语句更新到服务器。我是"后退"逻辑情况,当一个操作没有更新文档时,你回退到下一个:

<强>模型/ 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. 尝试匹配存在类别名称的文档,并更改&#34; UpdatedOn&#34;匹配数组元素的值。

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

  3. 如果没有更新。执行尝试匹配parentId的操作,只需将数组元素与upsert设置为true即可。由于之前的两次更新均失败,因此基本上是插入。

  4. 您可以使用async.waterfall之类的内容来传递numAffected值并避免缩进蠕变,或者个人不喜欢检查受影响的值并通过通过Bulk Operations API一次性向服务器发送所有语句。

    后者可以从像这样的猫鼬模型访问:

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

    注意反转逻辑,其中&#34; upsert&#34;首先发生,但如果成功,那么只有&#34;第二个&#34;声明将适用,但实际上在Bulk API下这不会影响文档。您将获得一个WriteResult对象,其基本信息与此类似(以简略形式):

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

    或者&#34; upsert&#34;:

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

    还要注意需要包含基本mongo驱动程序中的ObjectId函数,因为这是&#34; raw&#34;来自基本驱动程序的方法并没有&#34; autocast&#34;基于像mongoose方法那样的模式。

    另外要非常小心,因为它是一个基本的驱动程序方法,并且不共享mongoose逻辑,所以如果没有建立与数据库的连接,那么调用.collection访问器将不会返回{ {1}}对象和后续方法调用失败。猫鼬本身做了一个懒惰的&#34;数据库连接的即时化,方法调用排队&#34;直到连接可用。基本的驱动程序方法不是这样。

    所以它可以完成,只是你需要自己处理这种数组处理的逻辑,因为没有本地运算符可以做到这一点。但如果你采取适当的照顾,它仍然非常简单和有效。