mongodb update and push array of objects - mongodb

I have this simple collection of students:
{
"_id": "btv7865reVGlksabv",
"students": [
{
"name": "John",
"age": 30
},
{
"name": "Henry",
"age": 25
}
]
}
Now I want to push new students into this array:
const newStudents = [
{
"name": "Mike",
"age": 22
},
{
"name": "Kim",
"age": 20
}
]
What I tried so far is:
Students.update(
{
"_id": "btv7865reVGlksabv"
},
{
$push: {
"students": newStudents
}
}
);
The above query doesn't update my collection for some reason. Can anyone help me correct this query?

Chain up $push with $each
db.collection.update({
"_id": "btv7865reVGlksabv"
},
{
$push: {
"students": {
$each: [
{
"name": "Mike",
"age": 22
},
{
"name": "Kim",
"age": 20
}
]
}
}
})
Mongo Playground

Maybe something like this:
db.collection.update({},
[
{
$addFields: {
students: {
$concatArrays: [
"$students",
[
{
name: "New1",
age: "New1"
},
{
name: "New2",
age: "New2"
}
]
]
}
}
}
])
Explained:
Use $addFileds->$concatArrays to update via aggregation pipeline ( 4.2+) to add the elements from your new array to the already existing array ...
Playground

Related

Select and filter MongoDB subdocument array list

I am trying to select document with filter userInteractions array. I need to remove item where userdId = "633eb753c8e3d3fd71d1c254" and return document as result. It is easy way to approach it with MongoDB query?
https://mongoplayground.net/p/2UHw52QJkYu
Example of JSON document:
{
"_id": {
"$oid": "633c25965034208db76cfb1e"
},
"email": "test#test.com",
"users": [
{
"type": "person",
"isActive": true,
"userInteractions": [
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c254"
},
"firstName": "Tom",
"lastName": "Hawkins",
},
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c222"
},
"firstName": "Melan",
"lastName": "Key",
},
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c259"
},
"firstName": "Ken",
"lastName": "Olibar",
},
]
}
]
}
Expecting output:
{
"_id": {
"$oid": "633c25965034208db76cfb1e"
},
"email": "test#test.com",
"users": [
{
"type": "person",
"isActive": true,
"userInteractions": [
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c222"
},
"firstName": "Melan",
"lastName": "Key",
},
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c259"
},
"firstName": "Ken",
"lastName": "Olibar",
},
]
}
]
}
$set - Set users field.
1.1. $map - Iterate the users array and return a new array.
1.1.1. $mergeObjects - Merge the current iterated document and the document from the result 1.1.1.1.
1.1.1.1. $filter - Filter the document(s) from the userInteractions array from the current iterated document.
db.collection.aggregate([
{
$set: {
users: {
$map: {
input: "$users",
as: "user",
in: {
$mergeObjects: [
"$$user",
{
userInteractions: {
$filter: {
input: "$$user.userInteractions",
cond: {
$ne: [
"$$this.userId",
{
$toObjectId: "633eb753c8e3d3fd71d1c254"
}
]
}
}
}
}
]
}
}
}
}
}
])
Demo # Mongo Playground

MongoDB - Pivot data down instead of flattening with aggregation query

Can we unwind/flatten both old and new arrays and pivote data down like the below examples, consider both arrays might have different sizes and order. Looking for a solution in mongo aggregation query
Ex.1:
JSON/Object
{
"sno": "1001",
"owner": "Tim",
"old": [
{
"name": "John",
"age": "20"
},
{
"name": "Park",
"age": "40"
}
],
"new": [
{
"name": "Snow",
"age": "10"
},
{
"name": "Mike",
"age": "25"
},
{
"name": "New Rec",
"age": "55"
}
]
}
Output
sno owner current_name current_age renew_name renew_age
----------------------------------------------------------------------
1001 Tim John 20 Snow 10
1001 Tim Park 40 Mike 25
1001 Tim New Rec 55
Ex.2:
JSON/Object
{
"sno": "1001",
"owner": "Tim",
"old": [
{
"name": "John",
"age": "20"
},
{
"name": "Park",
"age": "40"
}
],
"new": [
{
"name": "Snow",
"age": "10"
}
]
}
Output
sno owner current_name current_age renew_name renew_age
----------------------------------------------------------------------
1001 Tim John 20 Snow 10
1001 Tim Park 40
$project to show required fields
$range to make array from 0 to total max element size of old or new array
$map to iterate loop of the above range
$arrayElemAt to select the object of the specific element from old and new array
$unwind deconstruct names array
$project to format your result and show required fields
db.collection.aggregate([
{
$project: {
sno: 1,
owner: 1,
names: {
$map: {
input: {
$range: [0,
{
$cond: [
{ $gt: [{ $size: "$old" }, { $size: "$new" }] },
{ $size: "$old" },
{ $size: "$new" }
]
}
]
},
in: {
old: { $arrayElemAt: ["$old", "$$this"] },
new: { $arrayElemAt: [ "$new", "$$this"] }
}
}
}
}
},
{ $unwind: "$names" },
{
$project: {
sno: 1,
owner: 1,
current_name: "$names.old.name",
current_age: "$names.old.age",
renew_name: "$names.new.name",
renew_age: "$names.new.age"
}
}
])
Playground

MongoDB: Summing the number of times a value == "Some String" in an object within an array

I have a MongoDB document that looks something like this:
{
"_id": 000000000001,
"sample": [
{
"_id": {
"$oid": "12345678910"
},
"Phone": 5555555555,
"LastName": "Musk",
"FirstName": "Elon",
"responses": {
"question1": "hello",
"question2": "world"
}
},
{
"_id": {
"$oid": "12345678911"
},
"Phone": "1111111111",
"LastName": "Jobs",
"FirstName": "Steve",
"responses": {
"question1": "goodbye",
"question2": "world"
}
}
]
}
I want to get a $sum of all the people who have given the response hello to question1 and all the people who have given the response world to question2.
For example. I want a response that looks something like this:
{ 'question1': 1, 'question2': 2 }
My query looks like this, but it isn't working. It's only returning 0 for any given sum when I know that's not the case.
db.collection(collection).aggregate([
{ $match : { } },
{ $group: {
_id: "responses",
"question1": { $sum: { $cond: [ { $eq: [ "$sample.responses.question1", "hello"] }, 1, 0 ] } },
"question2": { $sum: { $cond: [ { $eq: [ "$sample.responses.question2", "world"] }, 1, 0 ] } }
}
}
])
Can anyone help me out?

Aggregate query result in mongodb

I have collection with documents like this one:
{
"_id": 1,
"people": [
{
"name": "Bob",
"age": "15"
},
{
"name": "Alice",
"age": "18"
}
]
}
My query is:
db.groups.aggregate({ $match: { "_id": 1 }}, { $project: { "_id": 0, "people.name": 1 } })
This query returns:
{
"people": [
{
"name": "Bob"
},
{
"name": "Alice"
}
]
}
But I need the result like:
{ "names": [ "Bob", "Alice" ] }
Which parameters should I add to the .aggregate() function?
The solution is:
db.groups.aggregate({ $match: { "_id": 1 }}, { $project: { "_id": 0, "names": "$people.name" } })

Aggregation on complex objects

I have a collection with documents like the following:
{
"towers": [
{
"name": "foo",
"towers": [
{
"name": "A",
"buildType": "Apartament"
},
{
"name": "B",
"buildType": "Apartament"
}
]
},
{
"name": "xpto",
"towers": [
{
"name": "C",
"buildType": "House"
},
{
"name": "D",
"buildType": "Office"
}
]
}
]
}
All I need to know is what are all the possible values for "buildType", like:
Apartment
House
Office
It's a complex object and the data to aggregate is deep inside it. Is there any way to achieve the results I want?
You need to $unwind the two nested array that is "towers" and "towers.towers" and then use $group with "towers.towers.buildType" field to get the distinct values
db.collection.aggregate([
{ "$unwind": "$towers" },
{ "$unwind": "$towers.towers" },
{ "$group": {
"_id": "$towers.towers.buildType"
}}
])
Output
[
{
"_id": "Office"
},
{
"_id": "House"
},
{
"_id": "Apartament"
}
]
db.collection.aggregate(
// Pipeline
[
// Stage 1
{
$unwind: {
path: "$towers",
}
},
// Stage 2
{
$unwind: {
path: "$towers.towers",
}
},
// Stage 3
{
$group: {
_id: '$_id',
buildType: {
$addToSet: '$towers.towers.buildType'
}
}
},
]
);