MongoDB: geospatial query with additional conditions - mongodb

{ _id : ObjectId(...),
name : "...",
addresses : [ {
context : "home" ,
loc : [ 55.5, 42.3 ]
} ,
{
context : "office",
loc : [ -74 , 44.74 ]
}
]
}
address.loc is "2d" indexed.
I want to write a query that should give me all the document that are $near a location and the context is office.
I wrote some thing like:
db.coll.find({'address.loc':{$near:[lat,lng]}, 'address.context' : "office"});
Above query doesn't give me results that wanted. It searches for location in the entire "Address" array and then searches for context in the entire array.
I would like to search for same array location and same context. I know it could be done by $elemMatch but when I try to use it, it says there is no 2d index available or 2dsphere index.
I am new to MongoDB and not sure how should I write my query.

I've tried the query and it seems to work as you intend with the $elemMatch operator. I think the problem is that you have a typo in your query where address is used instead of addresses. Your query should look like:
db.coll.find({ 'addresses.loc':{$near:[lat,lng]}, addresses: { $elemMatch: {context: "office"} } });

Related

Search through a collection for documents which have a partial string in an array of strings

I've got a collection which has a bunch of documents which look like this:
{
"_id" : ObjectId("58d1d3e2b31da89828d0b194"),
"ihash" : "15e1e4b84492fe6f",
"firstseen" : ISODate("2017-03-22T01:31:14.405Z"),
"lastseen" : ISODate("2017-03-22T14:01:25.792Z"),
"names" : [
"carrot",
"apple",
"banana"
]
}
and I want to search through my collection to find all documents which contain "rr" in the list of names.
Any help with this would be great :)
You can use a mongo regex (see https://docs.mongodb.com/manual/reference/operator/query/regex/).
From the mongo console:
db.collection.find({ "names" : /rr/ })
or alternatively
db.collection.find({ "names" : {"$regex": /rr/ }})
You may want to check out the documentation for other options that are supported such as case-insensitive, matching anchors (^ for the start, $ for the end of the string), and others if your needs require it.

Why do I get this result from a multiple criteria query?

On mongo, I issue the following query:
db.usertest.find({ "events.event":"event0", "events.event":"event1", "events.event":"eventX" })
As per the docs here http://docs.mongodb.org/manual/tutorial/query-documents/#id4 I would expect this to only match documents that had all these three elements in an array.
However, it matches this doc:
{ "_id" : "userbruce", "events" : [ { "event" : "eventX" } ] }
Why?
The docs say that this format matches documents that "contain elements that in some combination satisfy the query conditions" What is matching event0 or event1?
EDIT: Is it getting confused because I put in the same field each time?
For AND operation in with this data, please try below query:
db.usertest.find({$and : [{ "events.event":"event0"}, {"events.event":"event1"}, {"events.event":"eventX" }]})
And yes, the confusion is because you given same field each time. IF you try something like below document:
{
"_id" : "userbruce",
"events" : [
{
"eventA" : "eventX"
},
{
"eventB" : "event0"
},
{
"eventC" : "event1"
}
]
}
then, your query would not have given any result. So, your query stands correct, but the data is not appropriate for that query.

creating covered index for aggregation framework

I have a problem with creating index for my query and can't find any similar solution on the web, so maybe some of you will help me.
To simplify problem let's say we have Phones with some attributes,
{
"type":"Samsung",
"model":"S3",
"attributes":[{
"value":"100",
"name":"BatteryLife"
},{
"value":"200$",
"name":"Price"
}
}
With index: {"type":1, "attributes.value":1}
We have millions of phones for every type and i want to find phones for given type that have given attributes, my query looks like:
db.Phone.aggregate([
{ "$match" : { "type" : "Samsung"}} ,
{ "$match" : { "attributes" : { "$all" : [
{ "value" : "100", "name" : "BatteryLife" } ,
{ "value" : "200$", "name" : "Price"}
]}
}
}
])
And it works !
The problem is that this query is highly inefficient, beacuse it use only first part of my index, that is "type"(and i have millions of phones of every type), and doesn't use 'attributes.value' part (type + attributes.value is almost unique, so it would reduce complexity significantly).
#Edit
Thanks to Neil Lunn i know it's because index is used only in my first match, so i have to change my query.
#Edit2
I think i found solution:
db.Phone.aggregate([
{$match: {
$and: [
{type: "Samsung"},
{attributes: {
$all: [
{ "value":"100", "type" : "BatteryLife" },
{ "value":"200$", "type" : "Price" }
]
}}
]}
}])
+db.Phone.ensureIndex({type:1, attributes:1}), seems to work. I think we can close now. Thanks for tip about $match.
To get the most out of the index you need to have a $match early enough in the pipeline that uses all the fields in the index. And avoid using $and operator since it's unnecessary and in the current (2.4) version can cause an index not to be fully utilized (luckily fixed for the upcoming 2.6).
However, the query is not quite correct as you need to use $elemMatch to make sure the same element is used to satisfy the name and value fields.
Your query should be:
db.Phone.aggregate([
{$match: { type: "Samsung",
attributes: { $all: [
{$elemMatch: {"value":"100", "type" : "BatteryLife" }},
{$elemMatch: {"value":"200$", "type" : "Price" }}
] }
}
}]);
Now, it's not going to be a covered query, since the attributes.value and name are embedded, not to mention the fact that name is not in the index.
You need the index to be {"type":1, "attributes.value":1, "attributes.name":1} for best performance, though it still won't be covered, it'll be much more selective than now.

query the value of a sub document in mongodb

I'm using the Java driver withe document that looks like this (a real test example):
{
"_id" : ObjectId("5207fe359b88bfa6f90a82b0"),
"meta_id" : "d6eb1b13-50c7-473f-8348-b5a638a542a0",
"name" : "Fake Name Inc.",
"created" : ISODate("2013-08-11T21:12:21.533Z"),
"members" : {
"5207fe359b88bfa6f90a82af" : [
"Admin",
"User"
]
}
}
I want to select the string array at the path "members.5207fe359b88bfa6f90a82af" (which is a list of roles).
I'm at a loss as to how to do that. It looks like a projection would work here, but I'm new enough to Mongo that the way the projection is written is not obvious.
I can of course load the whole object or maybe even just the "members" field, but I think I should be able to select just exactly the data I'm after.
So, does anyone have an idea of how such a query would be written?
Note: This question suggests that maybe I need to change the structure of the document to make things easier: MongoDB - Query by sub-tree
You can use dot notation in the projection parameter of find to do this. In the shell:
db.test.find(
{_id : ObjectId("5207fe359b88bfa6f90a82b0")},
{'members.5207fe359b88bfa6f90a82af': 1, _id: 0})
Returns:
{
"members": {
"5207fe359b88bfa6f90a82af": [
"Admin",
"User"
]
}
}

$all parameter in mongodb does not work with ObjectId list

I retrieve a list of ObjectId and I want to retrieve all object in my mongo database using the parameter $all
I'm using pymongo and my request look like this :
db.database.collection.find({ "_id" : { "$all" : [ObjectId('4ee371837c93dd33dc000003'),ObjectId('4eef9f647c93dd1a90000000')] } })
but the cursor count returned by the request is 0
but when I do this request:
db.database.collection.find_one({ "_id" : ObjectId('4ee371837c93dd33dc000003')})
It returns me the good object
Anyone know why it does not work?
That query does not make sense. You are asking for the unique and single-valued _id field to have all of two distinct values at the same time.
I think you want $in:
db.database.collection.find({ "_id" : {
"$in" :
[ObjectId('4ee371837c93dd33dc000003'),
ObjectId('4eef9f647c93dd1a90000000')] } })