How to update multiple documents with multiple condtions in MongoDB? - mongodb

I have a MongoDB collections with various documents. Now I have the input document Ids in an array of cars which I want to update. Something like this.
req.body =
{ cars: [ '584cf6c126df866138a29408', '5852819e9693c27c136104bd' ],
name: 'Home' },
{ cars: [ '584d638242795854a091cbbf', '5842e09e372b786355ba50e7' ],
name: 'Office' } ]
Expected Operation
db.cars.update({_id : req.body[i].cars}, {name : req.body[i].name}, {new : true});
Expected Result
All four documents with ids are updated with their name field in the document.
Now one way to update cars is to have an async.each applied on the array and an aysnc.each on these two documents. That's the longer way of doing it. I was hoping if I have one async.each for these two arrays and somehow could cramp both the documents in a single query it would make the code look more elegant.
I have already gone through several pages and still haven't found anything wanted to know if this is possible in mongo or not?

At first you may need to convert your car ids String type to mongodb ObjectId that means like:
cars: [ ObjectId'584cf6c126df866138a29408'), ObjectId'5852819e9693c27c136104bd') ]
then use $in operator to match with documents.
can try this.
var ObjectId = require('mongodb').ObjectID;
var cars = req.body[i].cars.map(function (id) {
return new ObjectId(id);
})
db.cars.update({_id : {$in: cars}},
{$set : {name : req.body[i].name}},
{multi : true},
function(err, docs) {
console.log(docs);
});

Try using $in of mongodb in find query while doing update. See query below:
Model.update({_id : {$in: req.body[i].cars}},
{$set : {name : req.body[i].name}},
{multi : true});
So this way you have to run 2 queries to update the names.
See $in-doc to know more about the uses.
Hope this will help you.

Related

Sort mongodb query on multiple fields

I would like to sort a mongodb query that search for bloggers.
Here the document structure (simplified) of a Blogger :
{
posts : {
hashtags : [{
hashtag : String,
weight : Number
}]
},
globalMark : Number
}
People can search bloggers via an input text. Eg: They can write "fashion travel" and click on search button.
I would like as result to show up Bloggers who have posts that contain hashtags that match /fashion/i and /travel/i, sorted by relevancy. The relevancy depends on the globalMark and hashtag weight.
I know how to show up them skipping hashtag weight but don't know how to include this weight in my query....
Here my current query :
Blogger.find({
"$and" : [{
"posts.hashtags.hashtag" : {$regex: /fashion/i}
}, {
"posts.hashtags.hashtag" : {$regex: /travel/i}
}]
})
.sort("-globalMark")
How can I handle this weight ?
BIG THANKS !
First think: MongoDB is not a for search with like operator (if your data is big you will have some latency).
Second think: hashtags value need to be object or objects in array
Third: You can use
db.collectionName.find({
$and: [
{"posts.hashtags.hashtag" : {$regex: /fashion/i}},
{"posts.hashtags.hashtag" : {$regex: /travel/i}}
]
}).sort({
globalMark: 1, "posts.hashtags.weight": 1
})
I have made it using mongodb aggregation and $project pipeline stage. Basically $project let you modify result doc so I have used it to build a score regarding different fields then sort the aggregation on this built score.
Here the doc :
https://docs.mongodb.com/manual/reference/operator/aggregation/project/

How to query Mongodb for embedded array

I have a mongodb structure like.
The structure of the place model
{.....
amenities: [
{
name: "wifi",
is_free: true
},
{
name: "projector",
is_free: false,
price: "50"
},
...........
...........
...........
]
.....}
I want to do a query where, I want to search for a place which is having some set of amenities exist in the place irrespective of the price & is_free fields. How can I do it inside the mongodb / mongoose query.
I want list of places which are having set of amenities like wifi and
projector as a output.
db.places.find({$and: [{'amenities.name': 'wifi'}, {'amenities.name':'projector'}])
It will find the places which have all amneties specified in an array ['wifi', 'projector'].
Hope it helps.
Please try executing following query
db.places.find({
amenities : {
$exist : true
},
amenities : {
$elemMatch : {
name : {
$in : ['wifi', 'projector']
}
}
}
})
In above mentioned query $exists operator will check for existence of amenities field in document and $elemMatch operator will match amenities array containing name field with following values
(1) wifi
(2) projector
Try below query for one option of name:
db.places.find({amenities: {$exists: true}, 'amenities.name':'wifi'})
Also can try this query, if multiple options to check for name:-
var findQuery = {amenities: {$exists: true}, 'amenities.name':'wifi' , 'amenities.name':'projector'}
db.places.find(findQuery);
Hope this will help you.

How to check if multiple documents exist

Is there such a query that gets multiple fields, and returns which of these exists in the collection?
For example, if the collection has only:
{id : 1}
{id : 2}
And I want to know which of [{id : 1} , {id : 3}] exists in it, then the result will be something like [{id : 1}].
You are looking for the $in-operator.
db.collection.find({ id: { $in: [ 1, 3 ] } });
This will get you any documents where the id-field (different from the special _id field) is 1 or 3. When you only want the values of the id field and not the whole documents:
db.collection.find({ id: { $in: [ 1, 3 ] } }, { _id: false, id:true });
If you want to check provided key with value is present or not in collection, you can simply check by matching values and combining conditions using $or operator.
By considering id is different than _id in mongo.
You can use $or to get expected output and query will be as following.
db.collection.find({$or:[{"id":1},{"id":3}]},{"_id":0,"id":1})
If you want to match _id then use following query:
db.collection.find({$or:[{"_id":ObjectId("557fda78d077e6851e5bf0d3")},{"_id":ObjectId("557fda78d077e6851e5bf0d5")}]}

Mongodb : How to find documents in which fields match an ObjectId or a string?

I have some documents in a collection in Mongodb :
{_id : ObjectId('533af69b923967ac1801e113'), fKey : '533aeb09ebef89282c6cc478', ... }
{_id : ObjectId('5343bd1e2305566008434afc'), fKey : ObjectId('5343bd1e2305566008434afc'), ...} }
As you can see my field fkey can be set by a string or an ObjectId.
I would like to get all documents which match '533aeb09ebef89282c6cc478' or ObjectId('5343bd1e2305566008434afc').
But if i run :
db.mycollection.find({fkey : '533aeb09ebef89282c6cc478'})
I only get the first document of the collection.
Is there a way to configure Mongodb in order to get all documents which match the request without checking the type ?
Thanks for your help.
Pierre
There are two options for you here.
You could use mongo's $or operator:
db.mycollection.find({
$or: [
{ fKey: '533aeb09ebef89282c6cc478' },
{ fKey: ObjectId( '533aeb09ebef89282c6cc478' ) }
]
})
The $or operator performs a logical OR operation on an array of two or more <expressions> and selects the documents that satisfy at least one of the <expressions>.
You could also use the $in operator:
db.mycollection.find({
fKey: {
"$in": [ '533aeb09ebef89282c6cc478', ObjectId( '533aeb09ebef89282c6cc478' ) ]
}
})
The $in operator selects the documents where the value of a field equals any value in the specified array.
It sounds to me like these inconsistencies are not meant to be there. I recommend going through your code and data pipelines and figure out who/what is inserting the fKey value with an unknown datatype.

MongoDB: Iterate over collection by key?

How can I iterate over all documents matching each value of a specified key in a MongoDB collection?
E.g. for a collection containing:
{ _id: ObjectId, keyA: 1 },
{ _id: ObjectId, keyA: 2 },
{ _id: ObjectId, keyA: 2 },
...with an index of { keyA: 1 }, how can I run an operation on all documents where keyA:1, then keyA:2, and so on?
Specifically, I want to run a count() of the documents for each keyA value. So for this collection, the equivalent of find({keyA:1}).count(), find({keyA:2}).count(), etc.
UPDATE: whether or not the keys are indexed is irrelevant in terms of how they're iterated, so edited title and description to make Q/A easier to reference in the future.
A simpler approach to get the grouped count of unique values for keyA would be to use the new Aggregation Framework in MongoDB 2.2:
eg:
db.coll.aggregate(
{ $group : {
_id: "$keyA",
count: { $sum : 1 }
}}
)
... returns a result set where each _id is a unique value for keyA, with the count of how many times that value appears:
{
"result" : [
{
"_id" : 2,
"count" : 2
},
{
"_id" : 1,
"count" : 1
}
],
"ok" : 1
}
I am not sure I get you here but is this what you are looking for:
db.mycollection.find({ keyA: 1 }).count()
Will count all keys with keyA being 1.
If that does not answer the question do think you can be a little more specific?
Do you mean to do an aggregation for all unique key values for keyA?
It may be implemented with multiple queries:
var i=0;
var f=[];
while(i!=db.col.count()){
var k=db.col.findOne({keyA:{$not:{$in:f}}}).keyA;
i+=db.col.find({keyA:k}).count();
f.push(k);
}
The sense of this code is to collect unique values of KeyA field of objects of col collection in array f, which will be result of operation. Unfortunately, for a while doing this operation you should block any operations, which will change col collection.
UPDATE:
All can be done much easier using distinct:
db.col.distinct("KeyA")
Thanks to #Aleksey for pointing me to db.collection.distinct.
Looks like this does it:
db.ships.distinct("keyA").forEach(function(v){
db.ships.find({keyA:v}).count();
});
Of course calling count() within a loop doesn't do much; in my case I was looking for key-values with more than one document, so I did this:
db.ships.distinct("keyA").forEach(function(v){
print(db.ships.find({keyA:v}).count() > 1);
});