【问题标题】:how to validate date range and insert new data in a single command如何验证日期范围并在单个命令中插入新数据
【发布时间】:2017-07-05 12:05:37
【问题描述】:

假设我有一个名为“rooms”的集合,其中包含 20 个文档,每个文档在“room_record”字段中都有一个“start_date”和“end_date”,现在我想在 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"
    }

感谢您的帮助,谢谢!

【问题讨论】:

    标签: mongodb nosql


    【解决方案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
    });
    

    【讨论】:

    • 嘿,谢谢您的回复,如果我将现有的子文档更改为数组字段,我可以知道我的方法是否有效?
    • 我认为您在更新中的查询条件不正确。 {"room_record":{"$elemMatch":{"room_record.start_date":{"$lt":data.startDate},"room_record.end_date":{"$gt":endDate}},"room_type":data .roomType}} 应该是 {"room_record":{"$elemMatch":{"start_date":{"$lt":data.startDate},"end_date":{"$gt":endDate}}},"room_type ":data.roomType}.
    • 好吧,现在终于可以使用了,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    相关资源
    最近更新 更多