MongoDB .Need to count fileds of an array - mongodb

I have a collection like below
{ _id: 1, zipcode: "63109", students: [
{ name: "john", school: 102, age: 10 },
{ name: "jess", school: 102, age: 11 },
{ name: "jeff", school: 108, age: 15 }
] }
{ _id: 2, zipcode: "63110", students: [
{ name: "ajax", school: 100, age: 7 },
{ name: "achilles", school: 100, age: 8 },
] }
{ _id: 3, zipcode: "63109", students: [
{ school: 100, age: 7 },
{ school: 100, age: 8 },
] }
{ _id: 4, zipcode: "63109", students: [
{ name: "barney", school: 102, age: 7 },
{ name: "ruth", school: 102, age: 16 },
] }
Note:Some document doesnot have name field.
I want to findout the count of name field.
Kindly suggest query to find count in mongo

You can do this with aggregation framework with $unwind. Let say your collection name is test:
db.test.aggregate(
{$unwind: '$students'},
{$match:{'students.name':{$exists:1}}},
{$group:{_id: '$students.name', count:{$sum:1}}},
{$project:{tmp:{name:'$_id', count:'$count'}}},
{$group:{_id:'Total Names', total:{$sum:1}, data:{$addToSet:'$tmp'}}}
)
Hope this is what you want!

You need to use the aggregation framework in this case.
The first aggregation step would be to use $unwind to turn the arrays into streams of documents.
Then you can use $group as a second aggregation step with $sum:1 to get the count of every name.
db.collection.aggregate([
{
$unwind: "$students"
},
{
$group: {
_id:"$students.name",
count: { $sum:1 }
}
}
]

This is doable through the aggregation framework
I'll assume your collection is called mycoll:
db.mycoll.aggregate([
{$unwind:'$students'},
{$group:{_id:'$name', 'count':{$sum:1}},
{$match:{'students.name':{$exists:1}}}
]);
References:
Aggregations http://docs.mongodb.org/manual/tutorial/aggregation-zip-code-data-set/
Exists: http://docs.mongodb.org/manual/reference/operator/query/exists/
Summing '1' essentially turns it into a count.

Related

Field combination in an array where another field is the same in MongoDB?

I want to find matches with the same gender and insert them into a new field array aka names but I am unable to solution using MongoDB. Or mongooese.
Input example:
db.students.insertMany([
{ id: 1, name: "Ryan", gender: "M" },
{ id: 2, name: "Joanna", gender: "F" },
{ id: 3, name: "Andy", gender: "M" },
{ id: 4, name: "Irina", gender: "F" }
]);
Desired output:
[
{ gender: "M", names: ["Ryan","Andy"]},
{ gender: "F", names: ["Joanna","Irina"]}
]
Note: the table has many records and I do not know those gender/name pairs in advance
I try this but no results. I don't know how I should write this query.
db.students.aggregate([
{
$group:{
names : {$push:"$name"},
}
},
{ "$match": { "gender": "$gender" } }
])
You did not specify how to group. Try this one:
db.students.aggregate([
{
$group: {
_id: "$gender",
names: { $push: "$name" }
}
},
{
$set: {
gender: "$_id",
_id: "$$REMOVE"
}
}
])

How can I get the projection of some fields of a specific document embedded in an array?

Consider the following (simplified) example:
{
_id: 1,
name: "Andrew",
role: "ATT",
Sesons: [
{
year: "2018-2019",
age: 20,
goals: 10
},
{
year: "2019-2020",
age: 21,
goals: 101
}]
}
{
_id: 2,
name: "Paul",
role: "DF",
Sesons: [
{
year: "2018-2019",
age: 15,
goals: 102
},
{
year: "2019-2020",
age: 16,
goals: 1
}]
}
How can I get this specific result from a query, based on {"Seasons.year": "2019-2020"} for example ?
{_id: 2, name: "Paul", role: "DF", Seasons: {age: 16}}
And how can I get this result from a query by getting an entire embedded document?
{_id: 2, name: "Paul", role: "DF", Seasons: {year: "2018-2019", age: 16, goals: 1}}
Thank you so much!
I apologize for the question, perhaps, not correctly formatted, but it is my first question about Stack Overflow.
You can use projection.You can query like following.
[
{
$match: {
"_id": 2
}
},
{
$project: {
_id: 1,
name: 1,
role: 1,
Sesons: {
$filter: {
input: "$Sesons",
cond: {
$eq: [
"$$this.year",
"2019-2020"
]
}
}
}
}
}
]
Working Mongo playground . Once you get your result, again use the $project to get only age with other fields. Eg :
{
$project: {
"Sesons.year": 0,
"Sesons.goals": 0
}
}

How Do I get saperated counts while grouping on multiple fields mongodb aggregation?

I have the following documents in my candidate collection.
candidates = [
{
name: "amit",
age: 21,
city: 'pune'
}
{
name: "rahul",
age: 23,
city: 'pune'
},
{
name: "arjun",
age: 21,
city: 'pune'
},
{
name: "rakesh",
age: 23,
city: 'pune'
},
{
name: "amit",
age: 22,
city: 'nashik'
}
]
I want to group by age and city fields and count the documents based on its sum independent of each other
I tried following query
candidate.aggregate([
{$group: {_id: {age: '$age', city: '$city'}, count: {$sum: -1}}}
{$sort: {count: -1}},
{$limit: 10}
])
which gives me count of combine results of age and city.
what I want instead
{
ages: [
{
age: 21,
count: 2
},
{
age: 23,
count: 2
},
{
age: 21,
count: 1
}
],
cities: [
{
city: 'pune',
count: 4
},
{
city: 'nashik',
count: 1
}
]
}
thanks for any help.
You need to use $facet stage, with a $group stage per age, and another per city.
Here's the query :
db.collection.aggregate([
{
$facet: {
byCity: [
{
$group: {
_id: {
city: "$city"
},
count: {
$sum: 1
}
}
},
{
$sort: {
count: -1
}
},
{
$limit: 10
}
],
byAge: [
{
$group: {
_id: {
age: "$age",
},
count: {
$sum: 1
}
}
},
{
$sort: {
count: -1
}
},
{
$limit: 10
}
]
}
},
])
Mongo playground

Querying Array of Embedded Documents in MongoDB based on Range

How can I query array of embedded document in mongodb.
{
_id: 1,
zipcode: "63109",
students: [
{ name: "john", school: 102, age: 14 },
{ name: "jess", school: 102, age: 11 },
{ name: "jeff", school: 108, age: 15 }
]
}
{
_id: 2,
zipcode: "63110",
students: [
{ name: "ajax", school: 100, age: 7 },
{ name: "achilles", school: 100, age: 8 },
]
}
{
_id: 3,
zipcode: "63109"
}
Let's say for the above data how will retrieve only those lines where age>=7 and age<=10. For id_1 only the row with age 10 should be returned. Both the rows in id_2 and id_3. Also, id_4 has no field called students. So, I DO NOT, want to see it in the output.
Edit:-
The output I get looks something like this when I do a filter. But I DO NOT want the row that has "None".
The last document _id: 3 does not have the field students but filtering is done on students, so the output has a "None" corresponding to it.
I wish to handle 2 cases:
No filtering should be applied where the array "students" don't exist under an id.
Array students exists but is empty []
Both these cases end up in the output if simply filtered.
{'_id': ObjectId('5cdaefd393436906b016ddb4'),
'students': [{'name': ajax,
'school': '100',
'age': '7'},
{'name': achilles,
'school': '100',
'age': '8'}],
{'_id': ObjectId('5cdaefd393436906b016ddb3'), 'students': None}
Note: I am using a different but identical data set, so the output is not exact, but I hope you get the idea. The 'student' is an embedded document which may or may not be present in all documents.
Edit : Finally I used unwind to achieve what I wanted.
You can use below aggregation
db.collection.aggregate([
{ "$match": { "$expr": { "$gte": [{ "$size": { "$ifNull": ["$students", []] } }, 1] }}},
{ "$addFields": {
"students": {
"$filter": {
"input": { "$ifNull": ["$students", []] },
"cond": {
"$and": [
{ "$gte": ["$$this.age", 7] },
{ "$lte": ["$$this.age", 10] }
]
}
}
}
}}
])

Mongodb : elemMatch

My problem cans be described as the following.
Give the following data (copied from mongo manual), how can i find the document which has zipcode 63109 and has 2 studends named "John", and "Jeff". I try
db.schools.find( { zipcode: 63109 },
{ students: { $elemMatch: { name : {"John", "Jeff"} } } } )
But it doesn't work. Could you help me, please ?
Thank you in advanced
{
_id: 1,
zipcode: 63109,
students: [
{ name: "john", school: 102, age: 10 },
{ name: "jess", school: 102, age: 11 },
{ name: "jeff", school: 108, age: 15 }
]
}
{
_id: 2,
zipcode: 63110,
students: [
{ name: "ajax", school: 100, age: 7 },
{ name: "achilles", school: 100, age: 8 },
]
}
{
_id: 3,
zipcode: 63109,
students: [
{ name: "ajax", school: 100, age: 7 },
{ name: "achilles", school: 100, age: 8 },
]
}
{
_id: 4,
zipcode: 63109,
students: [
{ name: "barney", school: 102, age: 7 },
]
}
I don't think it's possible to use $elemMatch here
The only solution I see is:
db.schools.find( { zipcode: 63109, $and: [{"students.name": "john"}, {"students.name": "jeff"}]} )