Querying Properties Array mongodb - mongodb

I am trying to get building by its id:
I have a collection called buildings:
{
"_id" : ObjectId("5b3b1cc79c23061e4d4634e4"),
"buildings" : [
{
"id" : 0,
"name" : "Farm",
"description" : "Best farm of all times",
"img" : "http://i.hizliresim.com/yq5g57.png",
"wood" : "50",
"stone" : "10"
},
{
"id" : 1,
"name" : "Storage",
"description" : "Store your resources.",
"img" : "http://i.hizliresim.com/yq5g47.png",
"wood" : "100",
"stone" : "200"
}
]
}
For example with id 0,i would like to get data of Farm.
I tried this:
db.getCollection('buildings').find({"buildings.id":0})
not working
sample output :
{
"id" : 0,
"name" : "Farm",
"description" : "Best farm of all times",
"img" : "http://i.hizliresim.com/yq5g57.png",
"wood" : "50",
"stone" : "10"
}
Tried:
var data = Buildings.find({},{buildings:{$elemMatch:{id:0}}}).fetch();
console.log(JSON.stringify(data));
result:(all data)
[{"_id":{"_str":"5b3b1cc79c23061e4d4634e4"},"buildings":[{"id":0,"name":"Farm","description":"Best farm of all times","img":"http://i.hizliresim.com/yq5g57.png","wood":"50","stone":"10"},{"id":1,"name":"Storage","description":"Store your resources.","img":"http://i.hizliresim.com/yq5g47.png","wood":"100","stone":"200"}]}]

You can use $filter aggregation to exclude the unwanted elements from the array
db.collection.aggregate([
{ "$match": { "buildings.id": 0 }},
{ "$project": {
"shapes": {
"$arrayElemAt": [
{ "$filter": {
"input": "$buildings",
"as": "building",
"cond": {
"$eq": [
"$$building.id",
0
]
}
}},
0
]
},
"_id": 0
}}
])

Try for this
db.getCollection("collectionName").find({buildings: {"$elemMatch": {"id" : "0"}}})
Here the find method will look(cursor) for the data with buildings and id=0

db.collection.find({
buildings: {
$elemMatch: {
id: 0
}
}
}, {
'buildings.$': 1
})

Related

match element in the array with aggregation

i have mongo db collection the follwing structure
{
{
"_id" : ObjectId("63e37afe7a3453d5014c011b"),
"schemaVersion" : NumberInt(1),
"Id" : "ObjectId("63e37afe7a3453d5014c0112")",
"Id1" : "ObjectId("63e37afe7a3453d5014c0113")",
"Id2" : "ObjectId("63e37afe7a3453d5014c0114")",
"collectionName" : "Country",
"List" : [
{
"countryId" : NumberInt(1),
"name" : "Afghanistan",
},{
"countryId" : NumberInt(1),
"name" : "India",
},
{
"countryId" : NumberInt(1),
"name" : "USA",
}
}
i need to match the value with id, id1, id2, collectionName and name in the list to get country id for example if match the below value
"Id" : "ObjectId("63e37afe7a3453d5014c0112")",
"Id1" : "ObjectId("63e37afe7a3453d5014c0113")",
"Id2" : "ObjectId("63e37afe7a3453d5014c0114")",
"collectionName" : "Country",
"name" : "Afghanistan",
i need result
{
"countryId" : 1,
"name" : "Afghanistan",
}
i tried like below
db.country_admin.aggregate([
{ $match: { collectionName: "Country" } },
{ $unwind : '$countryList' },
{ $project : { _id : 0, 'countryList.name' : 1, 'countryList.countryId' : 1 } }
]).pretty()
and i have following output
[
{
"List" : {
"countryId" : 1.0,
"name" : "Afghanistan"
}
},
{
"List" : {
"countryId" : 2.0,
"name" : "india"
}
},
{
"List" : {
"countryId" : 3.0,
"name" : "USA"
}
}]```
You can try using $filter to avoid $unwind like this example:
First $match by your desired condition(s).
Then $filter and get the first element (as "List.name": "Afghanistan" is used into $match stage there will be at least one result).
And output only values you want using $project.
db.collection.aggregate([
{
"$match": {
"Id": ObjectId("63e37afe7a3453d5014c0112"),
"Id1": ObjectId("63e37afe7a3453d5014c0113"),
"Id2": ObjectId("63e37afe7a3453d5014c0114"),
"collectionName": "Country",
"List.name": "Afghanistan",
}
},
{
"$project": {
"country": {
"$arrayElemAt": [
{
"$filter": {
"input": "$List",
"cond": {
"$eq": [
"$$this.name",
"Afghanistan"
]
}
}
},
0
]
}
}
},
{
"$project": {
"_id": 0,
"countryId": "$country.countryId",
"name": "$country.name"
}
}
])
Example here
By the way, using $unwind is also possible and you can check this example

MongoDB query using values priority

I have following documents in my collection:
/* 1 */
{
"_id" : ObjectId("5ea32d11f213c27c35395fd3"),
"name" : "Test",
"state" : "OH",
"code" : "CDM"
}
/* 2 */
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
/* 3 */
{
"_id" : ObjectId("5ea32d38f213c27c35395fe7"),
"name" : "Test2",
"state" : "OH",
"code" : "ALL"
}
/* 4 */
{
"_id" : ObjectId("5ea32d46f213c27c35395feb"),
"name" : "Test3",
"state" : "ALL",
"code" : "ALL"
}
Trying to filter documents based on state and code.
But there are few criteria if particular state or code is not found then search with value ALL
Example 1:
state = CA
code = CDM
then return only
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
Example 2:
state = CA
code = DCM
then return only
{
"_id" : ObjectId("5ea32d46f213c27c35395feb"),
"name" : "Test3",
"state" : "ALL",
"code" : "ALL"
}
etc..
The query that i tried was state = CA ,code = CDM:
db.getCollection('user_details').aggregate([
{'$match': { 'state': {'$in': ['CA','ALL']},
'code': {'$in': ['CDM','ALL']}}}
])
return was:
/* 1 */
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
/* 2 */
{
"_id" : ObjectId("5ea32d46f213c27c35395feb"),
"name" : "Test3",
"state" : "ALL",
"code" : "ALL"
}
Expected was :
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
Could you help to solve this issue.
Try below query :
db.collection.find({
$or: [
{
state: "CA",
code: "CDM"
},
{
state: "ALL",
code: "CDM"
},
{
state: "ALL",
code: "ALL"
},
{
state: "CA",
code: "ALL"
}
]
})
So basically you can not achieve what you're looking for in one query, you can try aggregation operator $facet & $switch to do this but I would not prefer to do that cause each stage in facet will do the given operation on entire collection's data. Instead get fewer docs using above query & in your code you can actually filter for best suited doc, Which would be easy & efficient. Don't forget to maintain indexes on DB.
Test : mongoplayground
Try this one:
db.user_details.aggregate([
{
$facet: {
match: [
{
"$match": {
$or: [
{
"state": "CA",
"code": {
"$in": [ "CDM", "ALL" ]
}
},
{
"state": {
"$in": [ "CA", "ALL"]
},
"code": "CDM"
}
]
}
}
],
all: [
{
"$match": {
"state": "ALL",
code: "ALL"
}
}
]
}
},
{
$project: {
match: {
$cond: [
{
$eq: [ { $size: "$match" }, 0]
},
"$all",
"$match"
]
}
}
},
{
$unwind: "$match"
},
{
$replaceWith: "$match"
}
])
MongoPlayground

Filter and count the number of element in an array [duplicate]

I have a mongoDB collection called "conference" with an array of participants as below :
[
{
"_id" : 5b894357a0c84d5a5d221f25,
"conferenceName" : "myFirstConference",
"startDate" : 1535722327,
"endDate" : 1535722420,
"participants" : [
{
"name" : "user1",
"origin" : "internal",
"ip" : "192.168.0.2"
},
{
"name" : "user2",
"origin" : "external",
"ip" : "172.20.0.3"
},
]
},
...
]
I would like to get the following result :
[
{
"conferenceName" : "myFirstConference",
"startDate" : 1535722327,
"endDate" : 1535722420,
"internalUsersCount" : 1
"externalUsersCount" : 1,
},
...
]
I tried the request below but it's not working :
db.getCollection("conference").aggregate([
{
$addFields: {
internalUsersCount : {
$size : { "$participants" : {$elemMatch : { origin : "internal" }}}
},
externalUsersCount : {
$size : { "$participants" : {$elemMatch : { origin : "external" }}}
}
}
}
])
How is it possible to count "participant" array elements that match {"origin" : "internal"} and {"origin" : "external"} ?
You need to use $filter aggregation to filter out the external origin and internal origin along with the $size aggregation to calculate the length of the arrays.
Something like this
db.collection.aggregate([
{ "$addFields": {
"internalUsersCount": {
"$size": {
"$filter": {
"input": "$participants",
"as": "part",
"cond": { "$eq": ["$$part.origin", "internal"]}
}
}
},
"externalUsersCount": {
"$size": {
"$filter": {
"input": "$participants",
"as": "part",
"cond": { "$eq": ["$$part.origin", "external"] }
}
}
}
}}
])
Output
[
{
"conferenceName": "myFirstConference",
"endDate": 1535722420,
"externalUsersCount": 1,
"internalUsersCount": 1,
"startDate": 1535722327
}
]

Mongodb Search with embedded document.

Structure of mongodb collection is like this.
collection User
{
"name":"sufaid",
"age":"22",
"address":"zzzz",
"product":[{"id":1,"name":"A"},
{"id":6,"name":"N"},
{"id":3,"name":"D"},
{"id":7,"name":"q"},
]
}
I need to find users those who have product id "3"
Out put should be like this
{
"name":"sufaid",
"age":"22",
"address":"zzzz",
"product":{"id":3,"name":"D"}
}
Note : With out using $unwind and projection like "product.$"
"product.$" through error while using pymongo.
Any other option is there ???
use $elemMatch. https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/
for your query:
db.User.find({},{name:1,age:1,address:1,product:{$elemMatch:{id:3}}})
or
db.User.find({},{product:{$elemMatch:{id:3}}})
o/p: {
"name" : "sufaid",
"age" : "22",
"address" : "zzzz",
"product" : [
{
"id" : 3.0,
"name" : "D"
}
]
}
As you require it for aggregation:
db.User.aggregate([
{$unwind:'$product'},
{$match:{'product.id':3}},
{$project:{_id:0,name:1,age:1,aaddress:1,product:1}}
])
o/p:
{
"name" : "sufaid",
"age" : "22",
"address" : "zzzz",
"product" : {
"id" : 3.0,
"name" : "D"
}
}
This will give exactly what you indicated in the question.
You could use the aggregation framework which has a plethora of operators that you can use, in particular you'd need the $filter and $arrayElemAt operators in a $project pipeline.
For instance, you could return just the product field as an embedded document by running the following pipeline:
db.user.aggregate([
{ "$match": { "product.id": 3 } },
{
"$project": {
"name": 1,
"age": 1,
"address": 1,
"product": {
"$arrayElemAt": [
{
"$filter": {
"input": "$product",
"as": "item",
"cond": { "$eq": [ "$$item.id", 3 ] }
}
},
0
]
}
}
}
])
Sample Output
{
"_id" : ObjectId("5829ac89628123dcf8a64b7a"),
"name" : "sufaid",
"age" : "22",
"address" : "zzzz",
"product" : {
"id" : 3,
"name" : "D"
}
}
If you just need an output with the array filtered, skip the $arrayElemAt expression and use the $filter only:
db.user.aggregate([
{ "$match": { "product.id": 3 } },
{
"$project": {
"name": 1,
"age": 1,
"address": 1,
"product": {
"$filter": {
"input": "$product",
"as": "item",
"cond": { "$eq": [ "$$item.id", 3 ] }
}
}
}
}
])
Sample Output
{
"_id" : ObjectId("5829ac89628123dcf8a64b7a"),
"name" : "sufaid",
"age" : "22",
"address" : "zzzz",
"product" : [
{ "id" : 3, "name" : "D" }
]
}
db.User.find({},{product:{$elemMatch:{id:3}}})
it's enough

Count same types element in array mongodb

{
_id:1, members: [
{
name:"John",
status:"A"
},
{
name:"Alex",
status:"D"
},
{
name:"Jack",
status:"A"
},
{
name:"Robin",
status:"D"
}
]}
That is Channel document.
Now I need to count all elements in members array where status equal to 'A'.
For example the above doc has 2 members with status 'A'.
How can I achieve this?
You can use mongodb-count to achieve the desired result.
Returns the count of documents that would match a find() query. The db.collection.count() method does not perform the find() operation but instead counts and returns the number of results that match a query.
So your query will be
var recordcount = db.collName.count({"members.status":"A"});
Now recordCount will be number of records that matches {"members.status":"A"} query.
Here Is your Json file
{
"_id" : ObjectId("575915653b3cc43fca1fca4c"),
"members" : [
{
"name" : "John",
"status" : "A"
},
{
"name" : "Alex",
"status" : "D"
},
{
"name" : "Jack",
"status" : "A"
},
{
"name" : "Robin",
"status" : "D"
}
]
}
And you want to the count of all elements in members array where
status equal to 'A'.
you have to try this one to find out your count
db.CollectionName.aggregate([{
"$project": {
"members": {
"$filter": {
"input": "$members",
"as": "mem",
"cond": {
"$eq": ["$$mem.status", "A"]
}
}
}
}
}, {
"$project": {
"membersize": {
"$size": "$members"
}
}
}]).pretty()
And you found your answer is like that { "_id" :
ObjectId("575915653b3cc43fca1fca4c"), "membersize" : 2 }
try this one for old version......
db.CollectionName.aggregate([{"$unwind":"$members"},{"$match":{"members.status":"A"}},{"$group":{_id:"$_id","memberscount":{"$sum":1}}}]).pretty()
{ "_id" : ObjectId("575915653b3cc43fca1fca4c"), "memberscount" : 2 }
Here Is your Json file
{
"_id" : ObjectId("575915653b3cc43fca1fca4c"),
"members" : [
{
"name" : "John",
"status" : "A"
},
{
"name" : "Alex",
"status" : "D"
},
{
"name" : "Jack",
"status" : "A"
},
{
"name" : "Robin",
"status" : "D"
}
]
}
And you want to the count of all elements in members array where
status equal to 'A'.
you have to try this one to find out your count
db.CollectionName.aggregate([{
"$project": {
"members": {
"$filter": {
"input": "$members",
"as": "mem",
"cond": {
"$eq": ["$$mem.status", "A"]
}
}
}
}
}, {
"$project": {
"membersize": {
"$size": "$members"
}
}
}]).pretty()
And you found your answer is like that { "_id" :
ObjectId("575915653b3cc43fca1fca4c"), "membersize" : 2 }