如果对象不存在,则将对象添加到对象数组中,否则更新对象

时间:2018-10-05 17:33:48

标签: node.js mongodb

期望的行为

将对象添加到对象数组(如果不存在),否则更新对象。

每个用户只能添加一个评分。

架构

"ratings" : [ 
    {
        "user_email" : "john@smith.com",
        "criteria_a" : 0,
        "criteria_b" : 3,
        "criteria_c" : 1,
        "criteria_d" : 5,
        "criteria_e" : 2
    },
    {
        "user_email" : "bob@smith.com",
        "criteria_a" : 1,
        "criteria_b" : 3,
        "criteria_c" : 5,
        "criteria_d" : 2,
        "criteria_e" : 1
    },
    {
        "user_email" : "jane@smith.com",
        "criteria_a" : 5,
        "criteria_b" : 3,
        "criteria_c" : 1,
        "criteria_d" : 0,
        "criteria_e" : 1
    }
]

我尝试过的事情

我已阅读:

  

$addToSet运算符将一个值添加到数组,除非该值是   已经存在,在这种情况下,$addToSet对该数组不执行任何操作。

来源:https://docs.mongodb.com/manual/reference/operator/update/addToSet/

但是我有点困惑,因为我认为我正在尝试:

  • $addToSet(如果对象不存在)
  • $set(即更新现有对象)(如果存在)

即使用户已经添加了评分,以下内容仍会向数组中添加rating个对象。

var collection = mongo_client.db("houses").collection("houses");

var o_id = new ObjectID(id);

var query = { _id: o_id, "ratings.user_email": user_email };

var update = { $addToSet: { ratings: rating } };

var options = { upsert: true };

collection.updateOne(query, update, options, function(err, doc) {
    if (err) {
        res.send(err);
    } else {
        res.json({ doc: doc })
    }
});

编辑:

如果用户已经提交了评分,则下面的方法有效,否则会引发错误The positional operator did not find the match needed from the query.

var update = { $set: { "ratings.$": rating } };

1 个答案:

答案 0 :(得分:1)

您将需要执行以下两个不同的操作:

  1. 如果尚无给定用户的评分,请尝试$push,即,像以前一样在更新查询的匹配部分中否定user_email
  2. 再次对"ratings.user_email": user_email进行匹配,但这次在$set上执行"ratings.$": rating

如果尚无该用户的评级,则将(1)插入,否则将不会进行任何操作。既然已保证存在该评级,(2)将确保该评级已更新。如果(1)插入了新的评分,则(2)只会导致不进行任何操作。

结果应如下所示:

collection.updateOne(
    { _id: o_id, ratings: { $not: { $elemMatch: { user_email: user_email } } } },
    { $push: { ratings: rating } }
);

collection.updateOne(
    { _id: o_id, "ratings.user_email": user_email },
    { $set: { "ratings.$": rating } }
);

下面是一个带有注释的详细示例:

// BEGIN new rating query/update variables
var query_new_rating = { _id: o_id, ratings: { $not: { $elemMatch: { user_email: user_email } } } };

var update_new_rating = { $push: { ratings: rating } };
// END new rating  query/update variables


//  part 01 - attempt to push a new rating
collection.updateOne(query_new_rating, update_new_rating, function(error, result) {

    if (error) {
        res.send(error);
    } else {

        // get the number of modified documents
        // if 0 - the rating already exists
        // if 1 - a new rating was added
        var number_modified = result.result.nModified;

        // BEGIN if updating an existing rating
        if (number_modified === 0) {

            console.log("updating existing rating");

            // BEGIN existing rating query/update variables
            var query_existing_rating = { _id: o_id, "ratings.user_email": user_email };

            var update_existing_rating = { $set: { "ratings.$": rating } };
            // END existing rating query/update variables

            //  part 02 - update an existing rating
            collection.updateOne(query_existing_rating, update_existing_rating, function(error, result) {

                if (error) {
                    res.send(error);
                } else {

                    console.log("updated existing rating");
                    res.json({ result: result.result })
                }

            });

        }
        // END if updating an existing rating

        // BEGIN if adding a new rating
        else if (number_modified === 1) {

            console.log("added new rating");
            res.json({ result: result.result })

        }
        // END if adding a new rating

    }
});