1

I am aware of a similar question available in SO but mine is little different Find values in mongdb. I am trying out a hotel booking app. Here I store the info about on which date the rooms are booked, which means the rooms are available in all other dates. I am working with mongodb and python.

I am using the $nin function. I have a option called alternate dates, where the user gives in another date. I want to display the availability of only one day that is, if room is available on the first date then the search should stop if not it should continue to the next date and give result if available.

This solution gives result for all the given dates. solution of Find values in mongdb

The data stored is

{
    "_id" : ObjectId("5645f0443f32df13e0dc786e"),
    "Booked Date" : ["28-9-2015","29-9-2015","1-10-2015"],
    "Room No.": "101"
},
{
    "_id" : ObjectId("5645f0c73f32df062064a0f6"),
    "Booked Date" : ["29-9-2015","1-10-2015"],
    "Room No.": "102"
},
{
    "_id" : ObjectId("5645f0c73f32df06205874f8"),
    "Booked Date" : ["29-9-2015","1-10-2015","2-10-2015"],
    "Room No.": "103"
},

I do the query like this

db.booking.find({"Date": { '$nin':[Date]}},{"_id": False,"Booked Date": False})

Here I give the input as ["1-10-2015","2-10-2015"]

So when I get the result I don't know on which date the room is available.

Is there a way I can solve this problem.

When I run this code

db.booking.find({"Date": { '$nin':["1-10-2015","2-10-2015"]}},{"_id": False,"Booked Date": False})

I get the result

{"Room No.": "101"}, 
{"Room No.": "102"}

But I dont know for which date the room is available. In the above case it is available only on 2-10-2015.

So is there a way to say that it is available on 2-10-2015.

And for another case:

db.booking.find({"Date": { '$nin':["1-10-2015","2-10-2015", "3-10-2015"]}},{"_id": False,"Booked Date": False})

Here it is available on 2-10-2015 & 3-10-2015, but it should show only the first availability date i.e 2-10-2015.

The output should be the same as above:

{"Room No.": "101"},
{"Room No.": "102"}
8
  • Your question is hard to understand please show the expected result. Commented Nov 16, 2015 at 5:51
  • @user3100115 please check the edit Commented Nov 16, 2015 at 8:54
  • @TonyRoczz I thought you need the first result.. but I guess you need only one room for each date if its available on that date. right? Commented Nov 16, 2015 at 9:05
  • @TonyRoczz if that is so.. I really doubt there may be a query to do that in mongo.. but you can counter that inside your python code.. just return room along with the dates they are available.. and strip down the rooms that are available on the same date.. :) Commented Nov 16, 2015 at 9:08
  • What about "Room No": 103 ? what should the result be? 3-10-2015? right? Commented Nov 16, 2015 at 9:27

1 Answer 1

0

You need to use the .aggregate() method.

You will need to use the $match operator to select document where the "Booked Date" is in your "date_list" then use the $project operator to return the the "Room No" and the corresponding list of "available date" using the $setDifference operator.

Then all you will need is handle the rest of the job client side.

from pprint import pprint
date_list = ["1-10-2015","2-10-2015", "3-10-2015"]
cur = collection.aggregate([
    {"$match": {"Booked Date": {"$in": date_list}}}, 
    {"$project": {
        "Room No": 1, 
        "available_date": {
            "$setDifference": [date_list, "$Booked Date"]
        }
    }}
])

Then using pprint.pprint to print the result:

pprint(list(cur))

which yields:

[{'Room No': '101',
  '_id': ObjectId('5645f0443f32df13e0dc786e'),
  'available_date': ['2-10-2015', '3-10-2015']},
 {'Room No': '102',
  '_id': ObjectId('5645f0c73f32df062064a0f6'),
  'available_date': ['2-10-2015', '3-10-2015']},
 {'Room No': '103',
  '_id': ObjectId('5645f0c73f32df06205874f8'),
  'available_date': ['3-10-2015']}]

Now another way of doing this which is less efficient is that you can denormalize your "available_date" array or list using the $unwind operator then $sort your result by "available_date" in ascending order. From there you will need to $group your document by "Room No" and use the $first operator to return the first date for each document.

As you can see this a lot more unnecessary work to the server and therefore is not a good solution.

cur = collection.aggregate([
    {"$match": {"Booked Date": {"$in": date_list}}},
    {"$project": {
        "Room No": 1, 
        "available_date": {
            "$setDifference": [date_list, "$Booked Date"]
        }
    }},
    {'$unwind': '$available_date'}, 
    {'$sort': {'avalable_date': 1}}, 
    {'$group': {
        '_id': '$Room No', 
        'available_date': {'$first': '$available_date'}
    }}
])
# pretty print the result
pprint(list(cur))

Which yields:

[{'_id': '102', 'available_date': '2-10-2015'},
 {'_id': '101', 'available_date': '2-10-2015'},
 {'_id': '103', 'available_date': '3-10-2015'}]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.