mongo query for multiple condition - mongodb

I have data,
var data = [{name: 'n1', age: 22}, {name: 'n1', age: age: 11}, {name: 'n2', age: age: 16}, {name: 'n3', age: 22}];
and I want to get data according to my multiple conditions:
condition 1:- var query = {name: 'n1', age: 22};
condition 2:- var query = {name = '', age: 22}
What I want with a single query:
If I run condition 1 then the result should be
[{name: 'n1', age: 22}].
and if I run condition 2, then the result should be
[{name: 'n1', age: 22}, {name: 'n3', age: 22} ].
Means for second condition, query should search only with age field.
That all I want to implement in one query.
I am doing like:
$query:{$and: [{name: query.name}, {age: query.age}]}
It works for first condition but not for second.
How can achieve it in one query?

Code it up so that only the fields you're interested in are in the query:
let criteria = [];
if (query.name && query.name.length > 0) {
criteria.push({ name: query.name });
}
if (query.age && query.age > 0) {
criteria.push({ age: query.age });
}
criteria = criteria.length > 0 ? { $and: criteria } : {};
Now you can pass your criteria to the query.

You could create a query object that can be initialised based on the two conditions above. The following snippet demonstrates this:
Populate test collection
db.test.insert([
{name: 'n1', age: 22},
{name: 'n1', age: 11},
{name: 'n2', age: 16},
{name: 'n3', age: 22}
])
Initialise conditions
var criteria = {},
condition = [
{"name": query.name},
{"age": query.age}
];
if (query.name !== "") { criteria["$and"] = condition; }
else { criteria["$or"] = condition; }
Test criteria for condition 1)
var query = {"name": "n1", "age": 22 }
printjson(criteria);
db.test.find(criteria);
Sample Output
{ "$and" : [ { "name" : "n1" }, { "age" : 22 } ] }
{ "_id" : ObjectId("56b341802ae7a05a8444cedc"), "name" : "n3", "age" : 22 }
Test criteria for condition 2)
var query = {"name": "", "age": 22 }
printjson(criteria);
db.test.find(criteria);
Sample Output
{ "$or" : [ { "name" : "" }, { "age" : 22 } ] }
{ "_id" : ObjectId("56b341802ae7a05a8444ced9"), "name" : "n1", "age" : 22 }
{ "_id" : ObjectId("56b341802ae7a05a8444cedc"), "name" : "n3", "age" : 22 }

Related

$elemMatch query in MongoDB

I have a collection 'name' with 2 documents of the structure :
doc 1:
{
a: 1
b : [{name:"AAA",age:10},
{name:"BBB",age:12},
{name:"CCC",age:13}]
}
doc 2 :
{
a: 2
b : [{name:"DDD",age:14},
{name:"EEE",age:15},
{name:"FFF",age:16}]
}
Since I am new to MongoDB, I am trying to find the difference of using the $elemMatch operator and not using it. Basically I am trying to query and find the first doc ( doc 1) with name AAA and age 10. So using the $elemMatch, my query looks like this :
db.name.find({b: {$elemMatch :{name:"AAA",age:10}}})
This query works perfectly fine, but my question is that what's the need to use this query when I can query like this :
db.name.find({b:{name:"AAA",age:10}})
I am sure there should be some reason for $elemMatch, just trying to find the difference. Thanks in advance for the reply !!!
The key difference is that the second query (without the $elemMatch) would only match elements in the b array that only contained those two fields, and only in that order.
So the first query would match the following two documents, but the second query wouldn't:
{
a: 1
b: [{name: "AAA", age: 10, city: 'New York'},
{name: "BBB", age: 12, city: 'Paris'},
{name: "CCC", age: 13, city: 'London'}]
}
{
a: 1,
b: [{age: 10, name: "AAA"},
{name: "BBB", age: 12},
{name: "CCC", age: 13}]
}
Another important difference is that how Mongo uses indexes.
If we have declared a multi-key-compound index:
db.name.createIndex({ "b.name": 1, "b.age": 1 })
And we execute this:
db.name.explain().find({
b: {
name: "DDD",
age: 14
}
})
we get:
"winningPlan" : {
"stage" : "COLLSCAN",
If we execute this:
db.name.explain().find({
b: {
$elemMatch: {
name: "DDD",
age: 14
}
}
})
we get:
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
But if we have a simple multi-key index in the array:
db.name.createIndex({b: 1})
The above index will be used in this query:
db.name.explain().find({
b: {
name: "DDD",
age: 14
}
})
And under my very un-professional profiling tests looks like this is faster.

Mongo update based on array index

I have a list of people in my database, where each person is one document. I would like to give them standard names (this is just for demo purposes – I don't care who gets which name so long as its unique).
I have an array of names to give them but I am not sure how to do this in Mongo. One simple way would be to just have a cursor and update the documents one by one, but that seems inefficient. Is there a better way to do this?
EDIT:
example db:
{id: 1234, age: 50}
{id: 1235, age: 40}
{id: 1236, age: 30}
Names:
['Bob', 'Jill', 'Gina']
Desired end state:
{id: 1234, age: 50, name: 'Bob'}
{id: 1235, age: 40, name: 'Jill'}
{id: 1236, age: 30, name: 'Gina'}
I'm not sure how you are specifying which names go with which _ids, so I'm going to assume you have a mapping specified in the following form:
> nameMapping
[{ "_id" : 1234, "name" : "Bob" }, { "_id" : 1235, "name" : "Jill" }, { "_id" : 1236, "name" : "Gina" }]
Then a good way to update every doc with a name is to use bulk operations. Bulk operations are supported in the drivers but I'll give the example in the mongo shell with bulk.find.update(), which is available as of MongoDB 2.6.
> var bulk = db.people.initializeUnorderedBulkOp()
> nameMapping.forEach(function(pair) {
bulk.find( { "_id" : pair._id } ).update( { $set: { "name" : pair.name } } )
})
> bulk.execute()

mongodb join-like query with two collections and a where clause

Suppose we have following collections in a database:
db.documents.insert([{'name': 'A'}, {'name': 'B'}, {'name': 'C'}])
db.fragments.insert([{'value:': 'A1', doc_name: 'A'}, {'value:': 'A2', doc_name: 'A'},
{'value:': 'B1', doc_name: 'B'}, {'value:': 'B2', doc_name: 'B'},
{'value:': 'C1', doc_name: 'C'}, {'value:': 'C2', doc_name: 'C'}])
where documents collection stores the names of the documents (and other stuff omitted in this example), fragments collections refers by doc_name to a document related to the fragment.
Now, if I only want to consider a subset of documents
> db.documents.find().limit(2)
{ "_id" : ObjectId("52d1a3bf49da25160ad6f076"), "name" : "A" }
{ "_id" : ObjectId("52d1a3bf49da25160ad6f077"), "name" : "B" }
then how can I see the fragments of associated to these selected documents, so I would get
{ "_id" : ObjectId("52d1a3bf49da25160ad6f079"), "value:" : "A1", "doc_name" : "A" }
{ "_id" : ObjectId("52d1a3bf49da25160ad6f07a"), "value:" : "A2", "doc_name" : "A" }
{ "_id" : ObjectId("52d1a3bf49da25160ad6f07b"), "value:" : "B1", "doc_name" : "B" }
{ "_id" : ObjectId("52d1a3bf49da25160ad6f07c"), "value:" : "B2", "doc_name" : "B" }
As a solution, I was thinking that I should store the document names in an array, something like var docnames = ??? such that
> docnames
[ "A", "B" ]
and then trying to use this array in a where clause, something like
> db.fragments.find({$where: function(x) { return (this.doc_name in docnames)}})
error: {
"$err" : "ReferenceError: docnames is not defined near 'c_name in docnames)}' ",
"code" : 16722
}
But as I am very new to mongodb, so I am having trouble figuring it out. I believe this could be done as a one-liner as well.
db.fragments.find( { 'doc_name': { $in : ['A' , 'B'] } } );
Execute this commands in mongo:
var f = db.documents.find().limit(2) , n = [];
for (var i = 0; i < f.length(); i++) n.push(f[i]['name']);
db.fragments.find( { 'doc_name': { $in : n } } );

Mongodb: find embedded element missing some key

I have a document with an embedded collection, but few elements are missing a key and I have to find all those elements. Here is an example:
var foo = {name: 'foo', embedded: [{myKey: "1", value: 3}, {myKey: "2", value: 3}]}
db.example.insert(foo)
var bar = {name: 'bar', embedded: [{value: 4}, {myKey: "3", value: 1}]}
db.example.insert(bar)
I need a query that returns the 'bar' object because one of its embedded doesn't have the key 'myKey'.
I try to use the $exists, but it returns only if ALL embedded elements are missing the key
db.example.find({'embedded.myKey': {$exists: true}}).size()
// -> 2
db.example.find({'embedded.myKey': {$exists: false}}).size()
// -> 0
How can I find the documents that at least one embedded element is missing the key 'myKey'?
If 'value' is always present, then you can try this command
db.example.find({ embedded : { $elemMatch : { value : {$exists : true}, myKey : {$exists : false}} }})
{ "_id" : ObjectId("518bbccbc9e49428608691b0"), "name" : "bar", "embedded" : [ { "value" : 4 }, { "myKey" : "3", "value" : 1 } ] }

Is possible to query mongodb on array keys?

My table has an array indexed by a string, and i want all the records matching this string, no matter what the value is. For example get all the record wher id1 is fill :
var a = {
type: "Information",
ids: {
'id1' : '123'
'id2' : '456'
}
};
var b = {
type: "Information",
ids: {
'id1' : '789'
}
};
Is it possible to do that with mongodb and how?
You can use $exists for this:
> db.things.insert({'type': 'Information', 'ids':{'id1': 123, 'id2': 456}})
> db.things.insert({'type': 'Information', 'ids':{'id1': 746, 'id2': 456}})
> db.things.insert({'type': 'Information', 'ids':{'id2': 456, 'id3': 936}})
> db.things.find({'ids.id1': {'$exists': true}})
{ "_id" : ObjectId("4dd3c706938307861ed610dd"), "type" : "Information", "ids" : { "id1" : 123, "id2" : 456 } }
{ "_id" : ObjectId("4dd3c7a1938307861ed610de"), "type" : "Information", "ids" : { "id1" : 746, "id2" : 456 } }
Thanks to scoates in #mondodb channel, it's possible to do that with exists function : http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24exists
db.Information.find({"ids.id1":{$exists:true}});