如何验证日期范围并在单个命令中插入新数据

时间:2014-08-16 16:19:39

标签: mongodb nosql

让我们说我有一个名为" 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"
    }

感谢您的帮助,谢谢!

1 个答案:

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