让我们说我有一个名为" room"包含20个文档,每个文档都有一个" start_date"和" end_date"在" room_record"字段,现在我想在room_record字段中插入一条新记录,但我希望检查新记录的开始和结束日期是否在现有记录start_date和end_date之间,如果它是重叠的,则查询必须失败或不插入新记录,否则插入新记录。我在这里找到了类似的问题 Query and Insert with a single command然而,我无法通过尝试他们的方法来解决我的问题。
这是我到目前为止所拥有的
会议室文件
{
"_id" : "0JikW3",
"room_capacity" : "2",
"room_description" : "bla bla bla",
"room_image" : [
"http://i.imgur.com/n99LkGg.jpg",
"http://i.imgur.com/zLPNy83.jpg"
],
"room_price" : "250",
"room_record" : {
"end_date" : "2014-08-18T13:54:52.891Z",
"start_date" : "2014-08-16T13:54:52.891Z"
},
"room_status" : "0",
"room_type" : "A"
}
这是我的方法
//build a record with new start and end date
var room_record = {
"booking_id":bookingID,
"start_date":data.startDate,
"end_date":endDate
}
rooms.update(
{"room_record":{"$elemMatch":{"room_record.start_date":{"$lt":data.startDate},"room_record.end_date":{"$gt":endDate}},"room_type":data.roomType}},
{ $setOnInsert:{"room_record":room_record}},
{upsert:1},
function(err,result){
if (err) return callback(err, null);
callback(err, result);
console.log(result)
})
执行我的方法后,这是我在我的房间集合中得到的,而不是插入到现有文档中,它创建了一个新文档。
{
"_id" : ObjectId("53ef765974574412ef7d0a49"),
"room_record" : {
"end_date" : ISODate("2014-08-21T13:54:52.891Z"),
"start_date" : "2014-08-19T13:54:52.891Z"
}
}
这是我预期的结果
{
"_id" : "0JikW3",
"room_capacity" : "2",
"room_description" : "bla bla bla",
"room_image" : [
"http://i.imgur.com/n99LkGg.jpg",
"http://i.imgur.com/zLPNy83.jpg"
],
"room_price" : "250",
"room_record" : [{
"end_date" : "2014-08-18T13:54:52.891Z",
"start_date" : "2014-08-16T13:54:52.891Z"
},{
"end_date" : ISODate("2014-08-21T13:54:52.891Z"),
"start_date" : "2014-08-19T13:54:52.891Z"
}],
"room_status" : "0",
"room_type" : "A"
}
感谢您的帮助,谢谢!
答案 0 :(得分:1)
$elemMatch only works for array field.
您的更新无法找到任何匹配的文档,因为您的room_record
是子文档,而不是数组。然后upsert影响插入新文档。
根据您期望的输出,我假设您想要将新记录推送到其文档可能存在的数组中,因此您不能像另一个问题那样采用$setOnInsert
。
以下代码提供您的信息,在mongo shell中运行。
var startDate = ISODate("2014-08-17T13:54:52.891Z");
var endDate = ISODate("2014-08-18T17:54:52.891Z");
var roomType = "A";
var room_record = {
"start_date" : startDate,
"end_date" : endDate
};
// check if any document overlapped by the time interval
db.rooms.find({
"room_record" : {
"$elemMatch" : {
"start_date" : {
"$lte" : startDate
},
"end_date" : {
"$gte" : endDate
}
}
},
"room_type" : roomType
}).forEach(printjson);
// Push new record into array field "room_record" if the record has not been overlapped by any element in the array.
// Please note that update will fail and produce an error if query succeeds and "room_record" exists but is not an array field.
// New document will be inserted into collection if no document matched.
db.rooms.update({
"room_record" : {
$not : {
"$elemMatch" : {
"start_date" : {
"$lte" : startDate
},
"end_date" : {
"$gte" : endDate
}
}
}
},
"room_type" : roomType
}, {
$push : {
"room_record" : room_record
}
}, {
upsert : true
});