MongoDB: Mapreduce necessary? Range query on dates in a booking application

Deadly 提交于 2019-12-11 09:43:45

问题


My collection has the following simplified (booking) schema:

{
    name: "room 1",
    from: ISODate("2014-06-10T12:00:00Z"),
    to: ISODate("2014-06-14T12:00:00Z")
 },
 {
    name: "room 1",
    from: ISODate("2014-06-25T12:00:00Z"),
    to: ISODate("2014-06-27T12:00:00Z")
 },
 {
    name: "room 2",
    from: ISODate("2014-06-12T12:00:00Z"),
    to: ISODate("2014-06-26T12:00:00Z")
 }

I'd like to query, if a room is available in a given range. For example I'd like to know if

  • room 1 is available FROM 2014-06-11 TO 2014-06-13
  • room 1 is available FROM 2014-06-13 TO 2014-06-26
  • room 1 is available FROM 2014-06-15 TO 2014-06-18

回答1:


Ok let's break this down, there are 4 ranges of booking conflicts:

  • start of another booking is before this start but the end is also before the end of this booking
  • start of another booking is after this start and the end is after this end
  • start of another booking is after this start and the end is before this end
  • start of other booking is before this start and after the end of this end

So you are looking for a query that can find all those ranges if they exist.

Now I set up this data:

> db.rooms.find()
{ "_id" : ObjectId("53ad206e1d8f2d8351182830"), "id" : 1, "from" : ISODate("2014-06-26T00:00:00Z"), "to" : ISODate("2014-06-28T00:00:00Z") }
{ "_id" : ObjectId("53ad276f1d8f2d8351182831"), "id" : 1, "from" : ISODate("2014-06-24T00:00:00Z"), "to" : ISODate("2014-07-01T00:00:00Z") }
{ "_id" : ObjectId("53ad28ad1d8f2d8351182832"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-06-28T00:00:00Z") }
{ "_id" : ObjectId("53ad28c61d8f2d8351182833"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-07-03T00:00:00Z") }
{ "_id" : ObjectId("53ad29971d8f2d8351182834"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-06-21T00:00:00Z") }

(the 5th range being a tester to make sure the query doesn't return random results)

And then I ran:

> db.rooms.find({from:{$lte: ISODate('2014-06-30T00:00:00.000Z')}, to:{$gte: ISODate('2014-06-23T00:00:00.000Z')}})
{ "_id" : ObjectId("53ad206e1d8f2d8351182830"), "id" : 1, "from" : ISODate("2014-06-26T00:00:00Z"), "to" : ISODate("2014-06-28T00:00:00Z") }
{ "_id" : ObjectId("53ad276f1d8f2d8351182831"), "id" : 1, "from" : ISODate("2014-06-24T00:00:00Z"), "to" : ISODate("2014-07-01T00:00:00Z") }
{ "_id" : ObjectId("53ad28ad1d8f2d8351182832"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-06-28T00:00:00Z") }
{ "_id" : ObjectId("53ad28c61d8f2d8351182833"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-07-03T00:00:00Z") }

If that query returns there are bookings and as such you cannot insert.

That should cover all bases I think, I am a little sleep deprived so I might be wrong.




回答2:


Considering your data is showing the dates on which the room is booked and you want to query for certain date ranges then you have to make sure that both these dates(for that you want to check availability for) lies outside the interval of "from" and "to" of the booked rooms, for that you have to run a query where both your input dates are either less than the "from" date or both are greater than the "to" date,this is how you do it

db.room.find({
 $or:[
  {$and : [{from:{$gt:new Date("2014-06-11T00:00:00.000Z")}},{to:{$gt:new Date("2014-06-13T00:00:00.000Z")}}]},
  {$and : [{from:{$lt:new Date("2014-06-11T00:00:00.000Z")}},{to:{$lt:new Date("2014-06-13T00:00:00.000Z")}}]}
    ]
})

if you want to count the room just add .count() to the above query and if you want to query for a specific room then just add "name":"roomname" in the above query.

Hope it helps.




回答3:


You can create range queries to check if from and to are within the searching dates. In addition the third use case is when the search dates cover one more documents' from/to interval.

My collection on which I performed tests looks like this:

> db.booking.find()
{ "_id" : ObjectId("53aa8d8cdfae7e8ccdd4b49d"), "name" : "room 1", "from" : ISODate("2014-06-10T12:00:00Z"), "to" : ISODate("2014-06-14T12:00:00Z") }
{ "_id" : ObjectId("53aa8da1dfae7e8ccdd4b49e"), "name" : "room 1", "from" : ISODate("2014-06-25T12:00:00Z"), "to" : ISODate("2014-06-27T12:00:00Z") }
{ "_id" : ObjectId("53aab77fe0cd5e6e1c56c08c"), "name" : "room 2", "from" : ISODate("2014-06-12T12:00:00Z"), "to" : ISODate("2014-06-26T12:00:00Z") }
{ "_id" : ObjectId("53ad1107d20cc7b2fe2df520"), "name" : "room 1", "from" : ISODate("2014-07-05T12:00:00Z"), "to" : ISODate("2014-07-07T12:00:00Z") }
{ "_id" : ObjectId("23ad1107d20cc7b2fe2df520"), "name" : "room 1", "from" : ISODate("2014-06-12T12:00:00Z"), "to" : ISODate("2014-06-26T12:00:00Z") }
>

Here are queries you can execute to check if a room is available (the return value of 0 means the room is available):

room 1 is available FROM 2014-06-11 TO 2014-06-13

db.booking.count({
    name:"room 1",
    $or:[
        { 
              from:{$lte:new Date("2014-06-11T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-06-11T00:00:00.000Z")}
        },
        {
              from:{$lte:new Date("2014-06-13T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-06-13T00:00:00.000Z")}
       },
       {
              from:{$gte:new Date("2014-06-11T00:00:00.000Z")}, 
              to:{$lte:new Date("2014-06-13T00:00:00.000Z")}
       }
]})

room 1 is available FROM 2014-06-13 TO 2014-06-26

db.booking.count({
    name:"room 1",
    $or:[
        { 
              from:{$lte:new Date("2014-06-13T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-06-13T00:00:00.000Z")}
        },
        {
              from:{$lte:new Date("2014-06-26T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-06-26T00:00:00.000Z")}
       },
       {
              from:{$gte:new Date("2014-06-13T00:00:00.000Z")}, 
              to:{$lte:new Date("2014-06-26T00:00:00.000Z")}
       }
]})

room 1 is available FROM 2014-06-15 TO 2014-06-18

db.booking.count({
    name:"room 1",
    $or:[
        { 
              from:{$lte:new Date("2014-06-15T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-06-15T00:00:00.000Z")}
        },
        {
              from:{$lte:new Date("2014-06-18T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-06-18T00:00:00.000Z")}
       },
       {
              from:{$gte:new Date("2014-06-15T00:00:00.000Z")}, 
              to:{$lte:new Date("2014-06-18T00:00:00.000Z")}
       }
]})

room 1 is available FROM 2014-07-02 TO 2014-07-09

db.booking.count({
    name:"room 1",
    $or:[
        { 
              from:{$lte:new Date("2014-07-02T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-07-02T00:00:00.000Z")}
        },
        {
              from:{$lte:new Date("2014-07-09T00:00:00.000Z")}, 
              to:{$gte:new Date("2014-07-09T00:00:00.000Z")}
       },
       {
              from:{$gte:new Date("2014-07-02T00:00:00.000Z")}, 
              to:{$lte:new Date("2014-07-09T00:00:00.000Z")}
       }
]})


来源:https://stackoverflow.com/questions/24403970/mongodb-mapreduce-necessary-range-query-on-dates-in-a-booking-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!