期望的行为
将对象添加到对象数组(如果不存在),否则更新对象。
每个用户只能添加一个评分。
架构
"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 } };
答案 0 :(得分:1)
您将需要执行以下两个不同的操作:
$push
,即,像以前一样在更新查询的匹配部分中否定user_email
。"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
}
});