How to query Mongodb for embedded array - mongodb

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.

Related

Mongo query - Array of Objects - get field from element 0 only

Trying to query Mongo, and get 1 field of element 0, inside a document, namely emails[0].address:
Here's a sample (truncated) document structure:
{
"_id" : "dfadgfe266reh",
"emails" : [
{
"address" : "email#domain.com",
"verified" : false
}
]
}
And my query (truncated) is like this:
{
fields: {
'emails.0.address': {
address: 1
}
}
}
However, when I run this, I get an empty object array, namely emails:[{}]
But if I change the selector to 'emails.address' it will give me the actual email address -- the problem is I only want emails[0].address
What am I doing wrong?
To get the required document you need a project document with two attributes. First one, as #Veeram mentioned, slices the array and second to specify an attribute from the embedded document in the array. See code:
db.collection.find( {}, { "emails": { $slice: 1 } , "emails.address": 1} );
You can use $ in projection:
.find({"emails.address":{$exists:true}}, {"emails.$.address":1})

How to update multiple documents with multiple condtions in 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.

I am building a mongoose aggregate for search mongodb documents

I built an aggregate for searching according to a filter. The things that the user can search for are optional, So is there any way to make the match optional - for example the user can select a date, If he didn't select, I want the aggregate function not to use match date
db.articles.aggregate(
[ {
$match : { date : userSelectedDate }, { else : elseSelection}
} ]
);
If no date is selected => cancel the date matching and match anothers
I would try to build the query document dynamically.
var query = []
if (userSelectedDate){
query.push({ $match : { date : userSelectedDate }})
db.articles.aggregate(query)
The solution was in mongoose documentation using: Aggregate#append(ops)
Appends new operators to this aggregate pipeline
after having the aggregate
aggregate.append({ $project: { field: 1 }}, { $limit: 2 });
so now I can use if(condition) before appending
mongoose documentation for append

Query MongoDB for multiple ObjectIDs in Array

I have a collection "users" in my Database. A user can be a member of several teams.
I am using an Array to reference the team IDs.
{ _id: ObjectId("552544fd600135861d9e47d5)",
name : "User1",
teams: [
"5527a9493ebbe2452666c238",
"5527b1be3371e3a827fa602c"
]
}
The teams are nothing more than a collection of:
{ _id: ObjectId("5527a9493ebbe2452666c238"),
name: "Team 1"
}
{ _id: ObjectId("5527b1be3371e3a827fa602c"),
name: "Team 2"
}
Now I want to get the names of all the teams in which the user is a member.
I have only found the way of querying it this way:
db.teams.find(
{_id:{$in:
[ObjectId("5527a9493ebbe2452666c238"),
ObjectId("5527b1be3371e3a827fa602c")]
}})
To do this, I would need to create an array specifically for this query. I would rather try to avoid this, because I already have the IDs available as an array in the string format. Something like this would be great:
db.teams.find(
{_id:{$in:
["5527a9493ebbe2452666c238",
"5527b1be3371e3a827fa602c"] // Strings here, not ObjectIDs
}})
But this does not work. Is there any comfortable way of querying an ObjectID with a set of string IDs?
Thanks & regards
Rolf
You could use a combination of mongodb's findOne() and find() cursor methods together with the native JavaScript map method to first get the team id's for a specific user (which will be a string array), then use the map function to map the teams' string id's array to an ObjectId's array, and finally query the teams collection with the resulting array as the $in operator expression:
var teams = db.users.findOne({"name": "User1"}).teams;
var obj_ids = teams.map(function (item){ return ObjectId(item)});
db.teams.find({ "_id": { "$in": obj_ids } });
Output:
/* 0 */
{
"_id" : ObjectId("5527a9493ebbe2452666c238"),
"name" : "Team 1"
}
/* 1 */
{
"_id" : ObjectId("5527b1be3371e3a827fa602c"),
"name" : "Team 2"
}

MongoDB select all where field value in a query list

How to achieve below SQL in MongoShell?
Select TableA.* from TableA where TableA.FieldB in (select TableB.FieldValue from TableB)
Mongo doc gives some example of
db.inventory.find( { qty: { $in: [ 5, 15 ] } } )
I want that array be dynamically from another query. Is it possible?
Extending my question
I have a collection of bot names
bots collection
{
"_id" : ObjectId("53266697c294991f57c36e42"),
"name" : "teoma"
}
I have a collection of user traffic, in that traffic collection, I have a field useragent
userTraffic Collection
{
"_id" : ObjectId("5325ee6efb91c0161cbe7b2c"),
"hosttype" : "http",
"useragent" : "Mediapartners-Google",
"is_crawler" : false,
"City" : "Mountain View",
"State" : "CA",
"Country" : "United States"
}
I want to select all user traffic documents where its useragent contains any name of bot collection
This is what I have come up with
var botArray = db.bots.find({},{name:1, _id:0}).toArray()
db.Sessions.find({
useragent: {$in: botArray}
},{
ipaddress:1
})
Here i believe it is doing equals to comparison, but I want it to do like %% comparison
Once I get the result, I want to do an update to that result set as is_crawler= true
Tried something like this, isn't helpful
db.bots.find().forEach( function(myBot) {
db.Sessions.find({
useragent: /myBot.name/
},{
ipaddress:1
})
});
Another way of looping through the records, but no match found.
var bots = db.bots.find( {
$query: {},
$orderby:{
name:1}
});
while( bots.hasNext()) {
var bot = bots.next();
//print(bot.name);
var botName = bot.name.toLowerCase();
print(botName);
db.Sessions.find({
useragent: /botName/,
is_crawler:false
},{
start_date:1,
ipaddress:1,
useragent:1,
City:1,
State:1,
Country:1,
is_crawler:1,
_id:0
})
}
Not in a single query it isn't.
There is nothing wrong with getting the results from a query and feeding that in as your in condition.
var list = db.collectionA.find({},{ "_id": 0, "field": 1 }).toArray();
results = db.collectionB.find({ "newfield": { "$in": list } });
But your actual purpose is not clear, as using SQL queries alone as the only example of what you want to achieve are generally not a good guide to answer the question. The main cause of this is that you probably should be modelling differently than as you do in relational. Otherwise, why use MongoDB at all?
I would suggest reading the documentation section on Data Modelling which shows several examples of how to approach common modelling cases.
Considering that information, then perhaps you can reconsider what you are modelling, and if you then have specific questions to other problems there, then feel free to ask your questions here.
Finally this is how I could accomplish it.
// Get a array with values for name field
var botArray = db.bots.find({},{name:1}).toArray();
// loop through another collection
db.Sessions.find().forEach(function(sess){
if(sess.is_crawler == false){ // check a condition
// loop in the above array
botArray.forEach(function(b){
//check if exists in the array
if(String(sess.useragent).toUpperCase().indexOf(b.name.toUpperCase()) > -1){
db.Sessions.update({ _id : sess._id} // find by _id
,{
is_crawler : true // set a update value
},
{
upsert:false // do update only
})
}
});
}
});