Mongo Array in Array Query - mongodb

Given the below example record, how can I find all users that belong to at least one group from an arbitrary set of groups to query against? For example, find all users that belong to any one of the following groups - 1, 10, 43. I'm looking for a generalized solution. I know I can build out an or query but is there a more efficient way to handle this?
> db.users.findOne()
{
"_id" : ObjectId("508f477aca442be537000000"),
"name" : "Some Name",
"email" : "some#email.com",
"groups" : [
1,5,10
]
}

{ groups: {$in: [1, 10, 43]} }

Related

Mongo: search sub array

Looking for users that are a part of a group.
Here is one user:
meteor:PRIMARY> db.users.find({_id:"rYHRMPpdXRa8fPXrj"})
Here is the result the single user:
{ "_id" : "rYHRMPpdXRa8fPXrj", "profile" : { "firstName" : "C", "groups" : [ "GJcqFCnSzfvJbuTMS", "gxD85kTiXmbtwaKfo" ]}
I try to find...
db.users.find({"groups":"rYHRMPpdXRa8fPXrj"})
db.users.find({"profile.groups":"rYHRMPpdXRa8fPXrj"})
db.users.find({profile:{"groups":"rYHRMPpdXRa8fPXrj"}})
db.users.find({"profile":{"groups":"rYHRMPpdXRa8fPXrj"}})
db.users.find({"profile":{"groups":["rYHRMPpdXRa8fPXrj"]}})
db.users.find({profile:{"groups":"rYHRMPpdXRa8fPXrj"}})
db.users.find({profile:{groups:"rYHRMPpdXRa8fPXrj"}})
db.users.find({profile:{groups:["rYHRMPpdXRa8fPXrj"]}})
db.users.find({profile:{$elemMatch:{groups:["rYHRMPpdXRa8fPXrj"]}}})
db.users.find({profile:{$elemMatch:{groups:"rYHRMPpdXRa8fPXrj"}}})
db.users.find({profile:{groups:{$in:["rYHRMPpdXRa8fPXrj"]}}})
I get nothing. ARRRG!!
How do I find all users in a specific profile.group?
You are passing your user _id into your query instead of the group id(?).
Try:
db.users.find({"profile.groups":"GJcqFCnSzfvJbuTMS"})
for example
$all should be used to filter by items within array:
db.users.find({profile:{groups:{$all:["rYHRMPpdXRa8fPXrj"]}}})

I have big database on mongodb and can't find and use my info

This my code:
db.test.find() {
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"title" : "Sir",
"name" : {
"_id" : ObjectId("4d3ed089fb60ab534684b7ff"),
"first_name" : "Farid"
},
"addresses" : [
{
"city" : "Baku",
"country" : "Azerbaijan"
},{
"city" : "Susha",
"country" : "Azerbaijan"
},{
"city" : "Istanbul",
"country" : "Turkey"
}
]
}
I want get output only all city. Or I want get output only all country. How can i do it?
I'm not 100% about your code example, because if your 'find' by ID there's no need to search by anything else... but I wonder whether the following can help:
db.test.insert({name:'farid', addresses:[
{"city":"Baku", "country":"Azerbaijan"},
{"city":"Susha", "country":"Azerbaijan"},
{"city" : "Istanbul","country" : "Turkey"}
]});
db.test.insert({name:'elena', addresses:[
{"city" : "Ankara","country" : "Turkey"},
{"city":"Baku", "country":"Azerbaijan"}
]});
Then the following will show all countries:
db.test.aggregate(
{$unwind: "$addresses"},
{$group: {_id:"$country", countries:{$addToSet:"$addresses.country"}}}
);
result will be
{ "result" : [
{ "_id" : null,
"countries" : [ "Turkey", "Azerbaijan"]
}
],
"ok" : 1
}
Maybe there are other ways, but that's one I know.
With 'cities' you might want to take more care (because I know cities with the same name in different countries...).
Based on your question, there may be two underlying issues here:
First, it looks like you are trying to query a Collection called "test". Often times, "test" is the name of an actual database you are using. My concern, then, is that you are trying to query the database "test" to find any collections that have the key "city" or "country" on any of the internal documents. If this is the case, what you actually need to do is identify all of the collections in your database, and search them individually to see if any of these collections contain documents that include the keys you are looking for.
(For more information on how the db.collection.find() method works, check the MongoDB documentation here: http://docs.mongodb.org/manual/reference/method/db.collection.find/#db.collection.find)
Second, if this is actually what you are trying to do, all you need to for each collection is define a query that only returns the key of the document you are looking for. If you get more than 0 results from the query, you know documents have the "city" key. If they don't return results, you can ignore these collections. One caveat here is if data about "city" is in embedded documents within a collection. If this is the case, you may actually need to have some idea of which embedded documents may contain the key you are looking for.

Pig load array to mongo

I would like to transform my output array:
I have the following code:
x = LOAD '$INPU'
USING PigStorage('\\u001')
AS (
product_id:chararray,
size:chararray
);
grouped = GROUP x BY (product_id);
sizes = FOREACH grouped {
sizes = DISTINCT $1.size;
GENERATE
$0 AS product_id,
sizes AS sizes;
}
output = foreach sizes generate
product_id as id,
sizes as sizes;
STORE output
INTO '$output'
USING com.mongodb.hadoop.pig.MongoInsertStorage('id');
this result the following:
"product_id" :"123",
"sizes": [
{
"size": "X"
},
{
"size": "M"
},
{
"size": "L"
}
]
It is possible to change the output to the following? :
product_id: "123",
sizes": ["X", "M", "L"]
i have tried flatten and BagToTuple but could not find a solution
thanks in advance
You've probably already seen it, but this page on mongodb.hadoop explains in great detail, and with examples, how to use MongoInsertStorage (and also MongoUpdateStorage).
I have to admit, I didn't see an option there to do what you'd like; indeed, in their example they get a similar result to yours.
However, on thing that might work is to use MongoUpdateStorage to do upserts. I'm not sure it will work, but if you use a general query with no parameters on a new or empty collection, it can do the job. If you look at the bottom part of the link I provided, they explain how to get output that looks like this
{ "_id" : ObjectId("..."), "gender":"male", "age" : 19, "cars" : ["a", "b", "c"], "first" : "Daniel", "last" : "Alabi" }
instead of this
{ "_id" : ObjectId("..."), "gender":"male", "age" : 19, "cars" : [{"car": "a"}, {"car":"b"}, {"car":"c"}], "first" : "Daniel", "last" : "Alabi" }
(I'm referring to the change in the cars field).
One last question - in your example, you change the name of product_id to id in your last foreach ... but in the output you showed, it still has the name product_id. Could it be you've been sending the wrong relation to MongoInsertStorage?
And, finally, another option is to save your collection as BSON and then use mongorestore on it - this option is also explained on that page.

MongoDB error on find()

I'm just started to create my MongoDB schema (im newbie on mongo), my schema looks like this example:
users : [
{
_id : 11,
name : "jhon",
mail : "jhon#mail.com"
},
{
_id : 12,
name : "smith",
mail: "smith#mail.com"
}
]
I want to retrieve certain user information, bsaed on a _id...
For example:
db.users.find({"users._id" : 11})
And then my result should be:
_id : 11,
name : "jhon",
mail : "jhon#mail.com"
but the result i get is all the users of the users document, i just one one, the one who have certaint _id.
How can i write a query for that?.
And just in case, my schema is designed properly?
Thanks for the help! :)
Try with this
db.users.find({"_id" : 11})
You ask whether your schema is designed properly. That of course depends on your use case, but the answer is probably... no. Instead of a single document with an array, probably what you want is multiple documents. For example, I inserted some documents using the mongo shell:
> db.users.insert({_id: 11, name: "jhon", mail: "jhon#mail.com"})
> db.users.insert({_id: 12, name: "smith", mail: "smith#mail.com"})
Then here's a query typed at the mongo shell that will return all documents:
> db.users.find()
{ "_id" : 11, "name" : "jhon", "mail" : "jhon#mail.com" }
{ "_id" : 12, "name" : "smith", "mail" : "smith#mail.com" }
And if you have the _id, you can query just that document:
> db.users.findOne({_id: 11})
{ "_id" : 11, "name" : "jhon", "mail" : "jhon#mail.com" }
Arrays have their uses, but the kind of thing you are doing here is usually done with multiple documents in a collection, rather than sub-documents within an array.
Does this help?

matching fields internally in mongodb

I am having following document in mongodb
{
"_id" : ObjectId("517b88decd483543a8bdd95b"),
"studentId" : 23,
"students" : [
{
"id" : 23,
"class" : "a"
},
{
"id" : 55,
"class" : "b"
}
]
}
{
"_id" : ObjectId("517b9d05254e385a07fc4e71"),
"studentId" : 55,
"students" : [
{
"id" : 33,
"class" : "c"
}
]
}
Note: Not an actual data but schema is exactly same.
Requirement: Finding the document which matches the studentId and students.id(id inside the students array using single query.
I have tried the code like below
db.data.aggregate({$match:{"students.id":"$studentId"}},{$group:{_id:"$student"}});
Result: Empty Array, If i replace {"students.id":"$studentId"} to {"students.id":33} it is returning the second document in the above shown json.
Is it possible to get the documents for this scenario using single query?
If possible, I'd suggest that you set the condition while storing the data so that you can do a quick truth check (isInStudentsList). It would be super fast to do that type of query.
Otherwise, there is a relatively complex way of using the Aggregation framework pipeline to do what you want in a single query:
db.students.aggregate(
{$project:
{studentId: 1, studentIdComp: "$students.id"}},
{$unwind: "$studentIdComp"},
{$project : { studentId : 1,
isStudentEqual: { $eq : [ "$studentId", "$studentIdComp" ] }}},
{$match: {isStudentEqual: true}})
Given your input example the output would be:
{
"result" : [
{
"_id" : ObjectId("517b88decd483543a8bdd95b"),
"studentId" : 23,
"isStudentEqual" : true
}
],
"ok" : 1
}
A brief explanation of the steps:
Build a projection of the document with just studentId and a new field with an array containing just the id (so the first document it would contain [23, 55].
Using that structure, $unwind. That creates a new temporary document for each array element in the studentIdComp array.
Now, take those documents, and create a new document projection, which continues to have the studentId and adds a new field called isStudentEqual that compares the equality of two fields, the studentId and studentIdComp. Remember that at this point there is a single temporary document that contains those two fields.
Finally, check that the comparison value isStudentEqual is true and return those documents (which will contain the original document _id and the studentId.
If the student was in the list multiple times, you might need to group the results on studentId or _id to prevent duplicates (but I don't know that you'd need that).
Unfortunately it's impossible ;(
to solve this problem it is necessary to use a $where statement
(example: Finding embeded document in mongodb?),
but $where is restricted from being used with aggregation framework
db.data.find({students: {$elemMatch: {id: 23}} , studentId: 23});