7

I'm trying to do a query(In MongoDB) in array("availability") that will return a only hotel that have the element("available") equals 1 and between the dates inside the availability.

But the query return all hotels when the correct return is "Mercato Hotel"

Query that i have used without success:

{city: "Boston", availability: { $elemMatch: {availability: 1, date: {$gte: ISODate("2015-05-02T00:00:00.000+0000")}, date: {$lte: ISODate("2015-05-04T00:00:00.000+0000")}}}}

Json in MongoDb:

 { 
        "_id" : ObjectId("55b302ee8debdf1a908cdc85"), 
        "city" : "Boston", 
        "hotel" : "Mercatto Hotel", 
        "availability" : [
            {
                "date" : ISODate("2015-05-01T00:00:00.000+0000"), 
                "available" : NumberInt(0)
            }, 
            {
                "date" : ISODate("2015-05-02T00:00:00.000+0000"), 
                "available" : NumberInt(0)
            }, 
            {
                "date" : ISODate("2015-05-03T00:00:00.000+0000"), 
                "available" : NumberInt(0)
            }, 
            {
                "date" : ISODate("2015-05-04T00:00:00.000+0000"), 
                "available" : NumberInt(1)
            }
        ]
    }
    { 
        "_id" : ObjectId("55b302ee8debdf1a908cdc89"), 
        "city" : "Boston", 
        "hotel" : "Hostel Villa", 
        "availability" : [
            {
                "date" : ISODate("2015-05-01T00:00:00.000+0000"), 
                "available" : NumberInt(1)
            }, 
            {
                "date" : ISODate("2015-05-02T00:00:00.000+0000"), 
                "available" : NumberInt(0)
            }, 
            {
                "date" : ISODate("2015-05-03T00:00:00.000+0000"), 
                "available" : NumberInt(0)
            }, 
            {
                "date: ISODate("2015-05-04T00:00:00.000+0000"), 
                "available" : NumberInt(0)
            }
        ]
    }

Someone can help me?

Thanks...

3 Answers 3

5

You have got a typo in your query, availability instead of available, should be this:

{
    city: "Boston", 
    availability: {
            $elemMatch: {
                    available: 1, 
                    date: {
                        $gte: ISODate("2015-05-02T00:00:00.000+0000"), 
                        $lte: ISODate("2015-05-04T00:00:00.000+0000")
                    }
            }
    }
}

UPDATE with Blakes Seven

If you want to get only the element of availability array that matches your query, add projection:

{
    "city": 1,
    "hotel": 1
    "availability.$.date": 1
}
Sign up to request clarification or add additional context in comments.

4 Comments

On the right track but basically the same as the OP's query. I think their gripe here is that the array in the document returned still has all the elements. So is there something you are not telling them here?
The OP wants a query "...that will return a only hotel that have the element("available") equals 1...". In that case the original query is just fine, but has an error in the field name. However if the requirement is that only the elements of the availability array are returned that have available as 0, then Vishwas' answer will perfectly work, if he adds a $group stage to the pipeline.
Or just show them how to use the positional $ operator to return the "one" match within the document array.
Updated, but if that's the case, the question needs to be redefined, agree? Thanks anyway.
4

The query:

{
    city: "Boston", 
    availability: {
            $elemMatch: {
                    available: 1, 
                    date: {
                        $gte: ISODate("2015-05-02T00:00:00.000+0000"), 
                        $lte: ISODate("2015-05-04T00:00:00.000+0000")
                    }
            }
    }
}

Returned the same result. In other words, returned all hotels when the correct return is "Mercato Hotel".

Comments

2

You can use aggregation to get expected output as following:

db.collection.aggregate({
    $unwind: "$availability"
}, {
    $match: {
    "city": "Boston",
    "availability.available": 1,
    "availability.date": {
        $gte: ISODate("2015-05-02T00:00:00.000+0000"),
        $lte: ISODate("2015-05-04T00:00:00.000+0000")
    }
    }
})

Edit

If there are multiple available=1 then use following query:

db.collection.aggregate({
    $unwind: "$availability"
}, {
    $match: {
    "city": "Boston",
    "availability.available": 1,
    "availability.date": {
        $gte: ISODate("2015-05-02T00:00:00.000+0000"),
        $lte: ISODate("2015-05-04T00:00:00.000+0000")
    }
    }
}, {
    $group: {
    _id: "$hotel",
    "city": {
        $first: "$city"
    },
    "availability": {
        $push: "$availability"
    }
    }
})

3 Comments

Aggregation is redundant here, and except the $unwind stage, the rest is the same as the OP's original query.
@n9code Aggregation is used to get only those documents where availability.available is 1. find will return all array containing availability.available = 0 as well as 1. In short it will return whole array if any match find.
I agree, but the the problem OP has is in his query itself, and he does not state that he/she needs only the element of the array that has available as 1. Besides if there are multiple elements with available equals 1, the result will be multiple document. So you will need to add a $group stage as well.

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.