Field combination in an array where another field is the same in MongoDB? - 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"
}
}
])

Related

Nodejs MongoDb add column to query that is a count of specific records

Considering the following document structure:
{_id: 1, name: 'joe', snapshot: null, age: 30}
{_id: 2, name: 'joe', snapshot: 'snapshot1', age: 30}
{_id: 3, name: 'joe', snapshot: 'snapshot15', age: 30}
{_id: 4, name: 'joe', snapshot: 'snapshot23', age: 30}
How would I perform a query that groups on the name field and adds an additional field that is a count of the remaining records containing subtree: 'additionalinfo'. It would look like this:
{_id: 1, name: 'joe', snapcount: 3, age: 30}
I've been able to group using aggregations but I can't quite get it like this.
My own solution:
I ultimately restructured my data to look like this instead:
{
_id: 1,
name: 'joe',
snapshots: [
{name: 'snap17', id: 1},
{name: 'snap15', id: 2},
{name: 'snap14', id: 3}
],
age: 30
}
This allows me to just check snapshots.length to solve my original problem. However; the answers in this post where very helpful and answered the original question.
Adding another aggregation query to do it: playground link: try it
db.collection.aggregate([
{
$match: {
"snapshot": {
$exists: true,
$ne: null
}
}
},
{
$group: {
_id: "$name",
snapcount: {
$sum: 1
},
age: {
"$first": "$age"
},
name: {
"$first": "$name"
}
}
},
{
"$unset": "_id"
}
])
Based on the comments, the query worked for OP:
db.collection.aggregate([
{
$match: {
"snapshot": {
$exists: true,
$ne: null
}
}
},
{
$group: {
_id: "$name",
snapcount: {
$sum: 1
},
age: {
"$first": "$age"
},
name: {
"$first": "$name"
},
id: {
"$first": "$_id"
}
}
},
{
"$unset": "_id"
}
])
Here's one way you could do it.
db.collection.aggregate([
{
"$group": {
"_id": "$name",
"name": {"$first": "$name"},
"age": {"$first": "$age"},
"snapcount": {
"$sum": {
"$cond": [
{"$eq": [{"$type": "$snapshot"}, "string"]},
1,
0
]
}
}
}
},
{"$unset": "_id"}
])
Try it on mongoplayground.net.

MongoDB - How to access a newly created array field created with $lookup and aggregate function

Assuming I have two collections:
courses:
[
{
_id: 1,
name: "Geometry",
teacher_id: 1
},
{
_id: 2,
name: "English",
teacher_id: 2
}
]
teachers:
[
{
_id: 1,
firstName: "John",
lastName: "Adams"
},
{
_id: 2,
firstName: "Mary",
lastName: "Jane"
}
]
Now I perform an aggregation on the two collections to create something similar to a join in SQL:
db.collection("courses").aggregate([
{
$lookup:{
from: "teachers",
localField: "teacher_id",
foreignField: "_id",
as: "teacher_info"
}
},
{
$match:{
//I want to perform a match or filter here on the teacher_info
}
}
]);
The $lookup and aggregation will return a list of documents that have a new teacher_info array field.
[
{
_id: 1,
name: "Geometry",
teacher_id: 1,
teacher_info: [
{
_id: 1,
firstName: "John",
lastName: "Adams"
},
]
},
{
_id: 2,
name: "English",
teacher_id: 1,
teacher_info: [
{
_id: 2,
firstName: "Mary",
lastName: "Jane"
},
]
}
]
I need to perform a match operation in the newly created teacher_info array field. For example, only keep the teacher that has the first name "John". How can I do so? Is that possible?
You can work with dot notation in your $match stage.
{
$match: {
"teacher_info.firstName": "John"
}
}
Demo # Mongo Playground

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
}
}

Getting the first created document and grouping by field name in MongoDB

I would like to get the very first department created for each company, however, I'm confused with the aggregate query.
Documents:
[
{
_id: "5b7579f2deea1c6e46fd9739",
name: "Sales",
companyId: "123",
},
{
_id: "5c5779f1dffe1c6e45df3973",
name: "Security",
companyId: "123",
},
{
_id: "5d9759f5ceda1c6e64df9772",
name: "Human Resource",
companyId: "789",
},
]
I'm expecting a result like this:
Expected Result:
[
{
_id: "5b7579f2deea1c6e46fd9739",
name: "Sales",
companyId: "123",
},
{
_id: "5d9759f5ceda1c6e64df9772",
name: "Human Resource",
companyId: "789",
},
]
But I'm getting only one result with my query.
Actual Result:
[
{
_id: "5b7579f2deea1c6e46fd9739",
name: "Sales",
companyId: "123",
},
]
Aggregate Query:
db.getCollection('departments').aggregate([
{
$sort:{ item: 1 }
},
{
$group: {
_id:'$item',
companyId: { $first:'$companyId'},
name: { $first:'$name'},
}
}
])
You need to group by companyId field like this:
db.departments.aggregate([
{
$group: {
_id: "$companyId",
doc: {
$first: "$$ROOT"
}
}
},
{
$replaceRoot: {
newRoot: "$doc"
}
}
])
Playground
If you have a natural sort field like a date field, it would be good to apply sort stage on that field before the group stage.

Nested grouping with MongoDB

Given a database the form of
[
{ gender: "m", age: 1, name: "A" },
{ gender: "f", age: 2, name: "B" },
{ gender: "m", age: 3, name: "C" },
{ gender: "f", age: 1, name: "D" },
{ gender: "m", age: 2, name: "E" },
{ gender: "f", age: 3, name: "F" },
{ gender: "m", age: 1, name: "G" },
{ gender: "f", age: 2, name: "H" },
{ gender: "m", age: 3, name: "I" },
{ gender: "f", age: 1, name: "J" }
]
I want to first group by age and secondly group by gender so that I get a nested result looking something like
[{
_id: "1",
children: [
{ _id: "f" },
{ _id: "m" }
]
}, {
_id: "2",
children: [
{ _id: "f" },
{ _id: "m" }
]
}, {
_id: "3",
children: [
{ _id: "f" },
{ _id: "m" }
]
}]
Here is what I tried so far:
db.example.aggregate(
{ $group: { _id: "$age", children: { $addToSet: {
age: "$age", gender: "$gender", name: "$name"
}}}},
{ $group: { _id: "$children.gender"}}
)
But this returns an {_id: null} as its result. Is this possible and in case yes, how?
Something like this should do it;
db.example.aggregate(
{
$group: {
_id: { age: "$age", gender: "$gender" },
names: { $addToSet: "$name" }
}
},
{
$group: {
_id: { age: "$_id.age" },
children: { $addToSet: { gender: "$_id.gender", names:"$names" } }
}
}
)
...which gives the result;
{
"_id" : {
"age" : 1
},
"children" : [
{ "gender" : "m", "names" : [ "G", "A" ] },
{ "gender" : "f", "names" : [ "J", "D" ] }
]
},
...
If you want the age as _id as in your example, just replace the second grouping's _id by;
_id: "$_id.age",