Aggregate the arrays in MongoDB - mongodb

I have a database structured like this:
{
"teams" : [
{
"best_players" : [
{
"contact" : {
"name" : "SomeName1"
},
"characteristic" : {
"skills" : "good"
}
}
],
"teamname" : "SomeTeam1"
},
{
"best_players" : [
{
"contact" : {
"name" : "SomeName2"
},
"characteristic" : {
"skills" : "bad"
}
}
],
"teamname" : "SomeTeam2"
}
]
}
I need to rename arrays and fields, and see the information in a different form.
What i'm expecting with aggregation-framework:
{
"team_players" : [
{
"player_name" : "SomeName1",
"player_skills" : "good" ,
"team_name" : "SomeTeam1"
},
{
"player_name" : "SomeName2",
"player_skills" : "bad" ,
"team_name" : "SomeTeam2"
}
]
}
What is the right way to query my result?

You can use $map within $project to format documents.
Something like
db.colname.aggregate(
{"$project":{
"team_players":{
"$map":{
"input":"$teams",
"in":{
"$let":{
"vars":{"best_player":{"$arrayElemAt":["$$this.best_players",0]}},
"in":{
"player_name":"$$best_player.contact.name",
"player_skills":"$$best_player.characteristic.skills",
"team_name":"$$this.teamname"
}
}
}
}
}
}})

Related

MongoDB join two collections with between clause

There is a collection "Printers":
{
"_id" : ObjectId("5cc02f9b9931de72296ba6c2"),
"model" : "Xerox WorkCentre 3315",
"serial" : "3255498494",
"date" : ISODate("2019-04-25T08:57:48.001+0000"),
"pages" : NumberInt(4868),
"location" : "New location",
"ip" : "10.159.0.35",
"ip_int" : NumberInt(178192419)
}
and "Branches" collection:
{
"_id" : ObjectId("5cb4799b8c0cfe35e4a4c266"),
"name" : "Office 1",
"ip_start" : NumberLong(178192384),
"ip_end" : NumberLong(178194431)
}
// ----------------------------------------------
{
"_id" : ObjectId("5cb479e68c0cfe35e4a4c269"),
"name" : "Office 2",
"ip_start" : NumberLong(3232258048),
"ip_end" : NumberLong(3232258303)
}
"Branches" collection contains ip addresses converted into integer value, i.e. 192.168.0.1 is 3232235521. Each record in Branches describes subnet.
Each printer located in one branch.
If printers.ip_int between branches record [ip_start;ip_end] then query should return all fields from Printer and one field "Name" from "Branches" collection.
How can i do this?
You need a lookup with custom pipeline where you can specify "between" condition:
db.Branches.aggregate([
{
$lookup: {
from: "Printers",
let: { ip_start: "$ip_start", ip_end: "$ip_end" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ "$gte": [ "$ip_int", "$$ip_start" ] },
{ "$lte": [ "$ip_int", "$$ip_end" ] },
]
}
}
}
],
as: "Printers"
}
}
])
db.getCollection("printers").aggregate(
[
{
"$lookup" : {
"from" : "branches",
"let" : {
"ip_int" : "$ip_int"
},
"pipeline" : [
{
"$match" : {
"$expr" : {
"$and" : [{"$gte" : ["$$ip_int", "$ip_start"]},
{ "$lte" : ["$$ip_int", "$ip_end"]}
]
}
}
}
], "as" : "Printers"
}
},
{
"$sort" : {
"ip_int" : 1.0
}
},
{
"$unwind" : {
"path" : "$Printers"
}
},
{
"$addFields" : {
"filial" : "$Printers.name"
}
},
{
"$project" : {
"Printers" : false, "ip_int" : false
}
}
]);

monogdb nested array items exact match

I have a collection as below what I want is to fetch the items that has exact match of Tag="dolore", I tried different ways but I am getting all the elements if any of the embedded element has tag as dolore
{
"_id" : 123,
"vendor" : "ut",
"boxes" : [
{
"boxRef" : 321,
"items" : [
{
"Tag" : "dolore",
},
{
"Tag" : "irure",
},
{
"Tag" : "labore",
}
]
},
{
"boxRef" : 789,
"items" : [
{
"Tag" : "incididunt",
},
{
"Tag" : "magna",
},
{
"Tag" : "laboris",
}
]
},
{
"boxRef" : 456,
"items" : [
{
"Tag" : "reprehenderit",
},
{
"Tag" : "reprehenderit",
},
{
"Tag" : "enim",
}
]
}
]
}
If you are expecting to get only the matching embedded documents you have $unwind, $match and then $group to reverse the $unwind. Like this:
db.getCollection('collectionName').aggregate([
{
$unwind:"$boxes"
},
{
$unwind:"$boxes.items"
},
{
$match:{
"boxes.items.Tag":"dolore"
}
},
{
$group:{
_id:{
boxRef:"$boxes.boxRef",
_id:"$_id"
},
vendor:{
"$first":"$vendor"
},
boxRef:{
"$first":"$boxes.boxRef"
},
items:{
$push:"$boxes.items"
}
}
},
{
$group:{
_id:"$_id._id",
vendor:{
"$first":"$vendor"
},
boxes:{
$push:{
boxRef:"$boxRef",
items:"$items"
}
}
}
},
])
Output:
{
"_id" : 123.0,
"vendor" : "ut",
"boxes" : [
{
"boxRef" : 321.0,
"items" : [
{
"Tag" : "dolore"
}
]
}
]
}

Mongodb Aggregation Pipeline Count Total size across multiple fields

`"ActivityScores" : {
"Spring" : [
{
"ActivityId" : "8fd38724-7e7d-4518-bd49-d38a8b4b3435",
"ActivityTime" : "2017-05-25T16:07:02.000-06:00"
}
],
"Winter" : [
{
"ActivityId" : "90d2a976-19d9-4ce0-aa88-d32c122d173b",
"ActivityTime" : "2017-02-14T22:50:00.000-06:00"
}
],
"Fall" : [
{
"ActivityId" : "84b8c41e-788f-4acd-abec-dc455285972b",
"ActivityTime" : "2016-11-15T22:37:02.000-06:00"
},
{
"ActivityId" : "157af880-d47b-42fc-8ecf-ecfc1bbb56b1",
"ActivityTime" : "2016-09-01T22:50:05.000-06:00"
}
]
},
"Grade" : "2",
"GradeTag" : "GRADE_2", `
I am looking for aggregation query to get Total of ActivityIds. I tried various combination of $group, $unwind, $size $addToset but none of them seems to be working . I need to find total activities using aggregation framework only. I don't want to go through each document using javascript or python to get the total counts. Is there any easy way around?
Thanks.We are on version 3.2.Finally below combination worked. ActivityScores was field to entity.SchoolYears in our Schema.Working Aggregation Pipeline for me.
db.studentcontentareadocument.aggregate(
[
{
$project: {
"SpringActivitiesPerDoc" : {
"$size" : "$entity.SchoolYears.ActivityScores.Spring"
},
"WinterActivitiesPerDoc" : {
"$size" : "$entity.SchoolYears.ActivityScores.Winter"
},
"FallActivitiesPerDoc" : {
"$size" : "$entity.SchoolYears.ActivityScores.Fall"
}
}
},
{
$project: {
"TotalActivitiesPerDoc" : {
"$add" : [
"$SpringActivitiesPerDoc",
"$WinterActivitiesPerDoc",
"$FallActivitiesPerDoc"
]
}
}
},
{
$group: {
"_id" : null,
"TotalActivities" : {
"$sum" : "$TotalActivitiesPerDoc"
}
}
},
{
$project: {
"_id" : 0,
"TotalSGPActivities" : "$TotalActivities"
}
}
],
{
cursor: {
batchSize: 50
},
allowDiskUse: true
}
);

How to check if nested arrays are ALL empty in mongodb?

I have something like below:
{
"_id" : "1",
"firstArray" : [
{
"_id" : "11",
"secondArray" : [ ]
},
{
"_id" : "12",
"secondArray" : [ ]
},
{
"_id" : "13",
"secondArray" : [ { "type" : "somthing" } ]
}
]
},
{
"_id" : "2",
"firstArray" : [
{
"_id" : "21",
"secondArray" : [ ]
},
{
"_id" : "22",
"secondArray" : [ ]
}
]
}
I need a mongodb query to find documents which ALL of the nested secondArrays are empty? the query should return second document and not the first one.
to solve that, we need to check size of arr2, but to enable that we need first to unwind arr1.
Please find below aggregation framework snippet which solves this problem,
db.pmoubed.aggregate([{
$unwind : "$firstArray"
}, {
$project : {
_id : 1,
firstArray : 1,
isNotEmpty : {
$size : "$firstArray.secondArray"
}
}
}, {
$group : {
_id : "$_id",
isNotEmpty : {
$sum : "$isNotEmpty"
},
firstArray : {
$push : "$firstArray"
}
}
}, {
$match : {
"isNotEmpty" : 0
}
}
])
Any comments welcome

Change field name in result Mongo Query

I have this Mongo query:
db.getCollection('Catalogos').aggregate(
{ $match: {Items: {$elemMatch: {'MarIclase': '04'} } } },
{ $unwind : "$Items" },
{ $match: { "Items.MarIclase" : "04" } },
{ $group : {
_id : "$_id",
Items : { $push : { 'MarIclase': "$Items.MarIclase", 'MarCdescrip' : '$Items.MarCdescrip' } }
}}
);
The result of this query is:
{
"result" : [
{
"_id" : "CAT_MARCAS_VU",
"Items" : [
{
"MarIclase" : "04",
"MarCdescrip" : "5500 LARSON"
},
{
"MarIclase" : "04",
"MarCdescrip" : "A LINER"
}
]
}
],
"ok" : 1.0000000000000000
}
I'd like to have this result:
{
"result" : [
{
"_id" : "CAT_MARCAS_VU",
"Items" : [
{
"04" : "5500 LARSON"
},
{
"04" : "A LINER"
}
]
}
],
"ok" : 1.0000000000000000
}
¿Do you know if I can make something in the $push and change the fieldnames for values?
I'd like to have something like this:
{ "04" : "A LINER" }
{ "04" : "5500 LARSON" }
Thank you!