Aggregation: Mongodb aggregation query example - mongodb

Record is database:
[
{
"title": "title1",
"author": [
{
"name": "user1",
"register": true
},
{
"name": "user2",
"register": true
}
],
"tags": [
"tag1",
"tag2",
"tag3"
]
},
{
"title": "title2",
"author": [
{
"name": "user1",
"register": true
},
{
"name": "user2",
"register": true
}
],
"tags": [
"tag1",
"tag2",
"tag3"
]
},
{
"title": "title3",
"author": [
{
"name": "user1",
"register": true
},
{
"name": "user2",
"register": true
}
],
"tags": [
"tag1",
"tag2",
"tag3"
]
}
]
expected output:
{"tag":"tag1", "titles":["title1","title2","title3"], "size":3}
{"tag":"tag2", "titles":["title2","title4"], "size":2}
Can someone help with aggregate query?

You can use group
$unwind to deconstruct the array
$group to regroup the based on tags
$project to show the desired output
Here is the code,
db.collection.aggregate([
{ "$unwind": "$tags" },
{
"$group": {
"_id": "$tags",
"titles": { "$push": "$title" }
}
},
{
$project: {
tag: "$_id",
titles: 1,
size: { $size: "$titles" },
_id: "$$REMOVE"
}
}
])
Working Mongo playground

Related

Adding a nested value as a field - MongDB aggregation

So I have a parent document with users, as well as an array that has users too. I want to add the DisplayName from the nested users array to the aggregation output. Any ideas?
Output I'm looking to achieve:
[
{
"user": {
"_id": "11",
"Name": "Dave",
"DocID": "1",
"DocDisplyName": "ABC"
},
{
"user": {
"_id": "33",
"Name": "Henry",
"DocID": "1",
"DocDisplyName": "ABC",
"BranchDisplayName:"BranchA"
}
}
]
And so on.. So an array of all users and for users that belong to a branch, add the branch display Name to the output.
// Doc 1
{
"_id": "1",
"DisplayName": "ABC",
"Users": [
{ "_id": "11", "Name": "Dave" },
{ "_id": "22", "Name": "Steve" }
],
"Branches": [
{
"_id": "111",
"DisplayName": "BranchA",
"Users": [
{ "_id": "33", "Name": "Henry" },
{ "_id": "44", "Name": "Josh" },
],
},
{
"_id": "222",
"DisplayName": "BranchB",
"Users": [
{ "_id": "55", "Name": "Mark" },
{ "_id": "66", "Name": "Anton" },
],
}
]
}
``Doc 2
{
"_id": "2",
"DisplayName": "DEF",
"Users": [
{ "_id": "77", "Name": "Josh" },
{ "_id": "88", "Name": "Steve" }
],
"Branches": [
{
"_id": "333",
"DisplayName": "BranchA",
"Users": [
{ "_id": "99", "Name": "Henry" },
{ "_id": "10", "Name": "Josh" },
],
},
{
"_id": "444",
"DisplayName": "BranchB",
"Users": [
{ "_id": "112", "Name": "Susan" },
{ "_id": "112", "Name": "Mary" },
],
}
]
}
Collection.aggregate([
{
$addFields: {
branchUsers: {
$reduce: {
input: "$Branches.Users",
initialValue: [],
in: {
$concatArrays: ["$$this", "$$value"],
},
},
},
},
},
{
$addFields: {
user: {
$concatArrays: ["$branchUsers", "$Users"],
},
},
},
{
$addFields: {
"user.DocID": "$_id","user.DocDisaplyName": "$DisplayName"
},
},
{
$unwind: "$user",
},
{
$project: {
_id: 0,
user: 1,
},
}
])
Thanks in advance!
OK I found a solution.
{
$addFields: {
"branchUsers.BranchDisplayName": {
$let: {
vars: {
first: {
$arrayElemAt: [ "$Branches", 0 ]
}
},
in: "$$first.DisplayName"
}
}
}
},
This creates the field only for the users that belong to the branch

Need to return matched data from mongo db JSON

I have Json which have values like state_city details this contains information like which city belongs to which state -
Need to query it for particular state name which will gives me all cities that belongs to that state.
db.collection.find({
"count": 10,
"state.name": "MP"
})
[
{
"collection": "collection1",
"count": 10,
"state": [
{
"name": "MH",
"city": "Mumbai"
},
{
"name": "MH",
"city": "Pune"
},
{
"name": "UP",
"city": "Kanpur"
},
{
"name": "CG",
"city": "Raipur"
}
]
},
{
"collection": "collection2",
"count": 20,
"state": [
{
"name": "MP",
"city": "Indore"
},
{
"name": "MH",
"city": "Bhopal"
},
{
"name": "UP",
"city": "Kanpur"
},
{
"name": "CG",
"city": "Raipur"
}
]
}
]
You have to use aggregate query to get only matching elements in array :
db.collection.aggregate([{
$unwind: "$content.state"
},
{
$match: {
"content.state.name": "MH",
"count": 10
}
},
{
$group: {
_id: "$content.state.city",
}
},
{
$addFields: {
key: 1
}
},
{
$group: {
_id: "$key",
cities: {
$push: "$_id"
}
}
},
{
$project: {
_id: 0,
cities: 1
}
}
])
This query will return :
{
"cities": [
"Pune",
"Mumbai"
]
}
The following query would be the solution.
db.collection.find({ "count": 10, "state":{"name": "MP"}})
For more complex queries, $elemMatch is also available.

Aggregate nested arrays

I have multiple documents, and I'm trying to aggregate all documents with companyId = xxx and return one array with all the statuses.
So it will look like this:
[
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
},
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
},
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
},
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
}
]
The document look like this:
[
{
"companyId": "xxx",
"position": "",
"section": "",
"comment": "",
"items": [
{
"any": "111",
"name": "some name",
"description": "some description",
"version": "3",
"status": [
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
}
]
},
{
"any": "222",
"name": "some name",
"description": "some description",
"version": "3",
"status": [
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
}
]
}
]
},
{
"companyId": "xxx",
"position": "",
"section": "",
"comment": "",
"items": [
{
"any": "111",
"name": "some name",
"description": "some description",
"version": "3",
"status": [
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
}
]
},
{
"any": "222",
"name": "some name",
"description": "some description",
"version": "3",
"status": [
{
"status": "created",
"date": "2019-03-16T10:59:59.200Z"
},
{
"status": "completed",
"date": "2019-03-16T11:00:37.750Z"
}
]
}
]
}
]
Any suggestion, how to implement this?
Then I want to loop over the array (in code) and count how many items in status created, and completed. maybe it could be done with the query?
Thanks in advance
You can use below aggregation:
db.col.aggregate([
{
$match: { companyId: "xxx" }
},
{
$unwind: "$items"
},
{
$unwind: "$items.status"
},
{
$replaceRoot: {
newRoot: "$items.status"
}
},
{
$group: {
_id: "$status",
count: { $sum: 1 }
}
}
])
Double $unwind will return single status per document and then you can use $replaceRoot to promote each status to root level of your document.
Additionally you can add $group stage to count documents by status.
In addition to the #mickl answer, you can add $project pipeline to get the result as a flat list of status and count.
db.collectionName.aggregate([
{
$match: { companyId: "xxx" }
},
{
$unwind: "$items"
},
{
$unwind: "$items.status"
},
{
$replaceRoot: {
newRoot: "$items.status"
}
},
{
$group: {
_id: "$status",
count: { $sum: 1 }
}
},
{
$project: {
"status":"$_id",
"count":1,
_id:0
}
}
])
If the number of documents on which you are executing the above query is too much then you should avoid using $unwind in the initial stage of aggregation pipeline.
Either you should use $project after $match to reduce the selection of fields or you can use below query:
db.col.aggregate([
{
$match: {
companyId: "xxx"
}
},
{
$project: {
_id: 0,
data: {
$reduce: {
input: "$items.status",
initialValue: [
],
in: {
$concatArrays: [
"$$this",
"$$value"
]
}
}
}
}
},
{
$unwind: "$data"
},
{
$replaceRoot: {
newRoot: "$data"
}
}
])

Aggregation collection in mongdb

How to populate in result of aggregated query in monogdb
Array of followedId
var followeduserId = ["abc","efg","xyz","pqr","acd","rts"];
Feeds Recommended
[
{
"feedsId": "feed1",
"userId": "abc"
},
{
"feedsId": "feed1",
"userId": "efg"
}
]
Feeds collection
[
{
"link": "www.yodo.com",
"recommended": [
"abc",
"efg"
],
"title": "This is my feed7",
"topics": [
"topi1",
"topi2",
"topi3",
"topi4"
]
},
{
"link": "www.yodo.com",
"recommended": [
"abc",
"efg",
"das",
"asd",
"eqw",
"weq"
],
"title": "This is my feed8",
"topics": [
"topi1",
"topi2",
"topi3",
"topi4"
]
}
]
Ran aggregation query
feedsrecommended.aggregate([
{ $match: { userId: { $in: "followersId" }}},
{ $lookup: {
from: "feeds",
localField: "feedsId",
foreignField: "_id",
as: "feedsId"
}},
{ $group: {
"_id": { "feedsId": "$feedsId" },
"count": { "$sum": 1 }
}},
{ $sort: { count: -1 }}
])
result After aggregation
var resultfeeds = [
{
"count": 7,
"id": {
"_id": "feed1",
"link": "www.yodo.com",
"recommended": [
"abc",
"efg",
"xyz",
"pqr",
"acd",
"rts"
],
"title": "This is my feed1",
"topics": [
"topi1",
"topi8",
"topi6",
"topi5"
]
}
},
{
"count": 3,
"id": {
"_id": "feed5",
"link": "www.yodo.com",
"recommended": [
"abc",
"efg",
"acd",
"rts"
],
"title": "This is my feed1",
"topics": [
"topi1",
"topi2",
"topi3",
"topi4"
]
}
},
{
"count": 3,
"id": {
"_id": "feed6",
"link": "www.yodo.com",
"recommended": [
"abc",
"efg",
"xyz",
"pqr"
],
"title": "This is my feed1",
"topics": [
"topi7",
"topi1",
"topi4",
"topi8"
]
}
},
{
"count": 2,
"id": {
"_id": "feed2",
"link": "www.yodo.com",
"recommended": [
"abc",
"acd",
"rts"
],
"title": "This is my feed1",
"topics": [
"topi7",
"topi6",
"topi8"
]
}
},
{
"count": 2,
"id": {
"_id": "feed7",
"link": "www.yodo.com",
"recommended": [
"abc",
"efg"
],
"title": "This is my feed1",
"topics": [
"topi1",
"topi5",
"topi6",
"topi4"
]
}
},
{
"count": 1,
"id": {
"_id": "feed3",
"link": "www.yodo.com",
"recommended": [
"abc",
"asd",
"eqw",
"weq"
],
"title": "This is my feed1",
"topics": [
"topi1",
"topi7",
"topi6",
"topi4"
]
}
},
{
"count": 1,
"id": {
"_id": "feed8",
"link": "www.yodo.com",
"recommended": [
"abc",
"das",
"asd",
"eqw",
"weq"
],
"title": "This is my feed1",
"topics": [
"topi1",
"topi2",
"topi5",
"topi4"
]
}
}
]
I want to populate topics and recommeded userName and image in the result
topic collection
[
{
"topic_name": "tiger"
},
{
"topic_name": "loin"
}
]
user collection
[
{
"name": "deepa",
"profileImg": "www.com/facebook.jpg"
},
{
"name": "nisa",
"profileImg": "www.com/facebook.jpg"
}
]
My last result should be like this
[
{
"count": 2,
"id": {
"_id": "feed2",
"link": "www.yodo.com",
"recommended": [
{
"_id": "abc",
"name": "deepa",
"profileImg": "www.com/facebook.jpg"
},
{
"_id": "acd",
"name": "sigger",
"profileImg": "www.com/facebook.jpg"
},
{
"_id": "rts",
"name": "buster",
"profileImg": "www.com/facebook.jpg"
}
],
"title": "This is my feed1",
"topics": [
{
"_id": "topi6",
"topic_name": "boolena"
},
{
"_id": "topi7",
"topic_name": "mika"
},
{
"_id": "topi8",
"topic_name": "tika"
}
]
}
}
]
You can try below aggregation in mongodb 3.6 and above
Feedsrecommended.aggregate([
{ "$match": { "userId":{ "$in": followersId }}},
{ "$group": {
"_id": "$feedsId",
"count": { "$sum": 1 }
}},
{ "$lookup": {
"from": "feeds",
"let": { "feedsId": "$_id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$feedsId" ] }}},
{ "$lookup": {
"from": "topics",
"let": { "topics": "$topics" },
"pipeline": [
{ "$match": { "$expr": { "$in": [ "$_id", "$$topics" ] } } }
],
"as": "topics"
}},
{ "$lookup": {
"from": "users",
"let": { "recommended": "$recommended" },
"pipeline": [
{ "$match": { "$expr": { "$in": [ "$_id", "$$recommended" ] } } }
],
"as": "recommended"
}}
],
"as": "feedsId"
}}
])

MongoDB aggregate results into nested array

I'm quite new to MongoDB and I am currently facing a situation. Below are 2 sample records from the whole database that I have :
{
"_id": 1,
"Record": 1,
"Link": [ "https://wikileaks.org/plusd/cables/1979PANAMA06344_e.html" ],
"Location": [ "USA", "PAN", "USA", "USA", "PAN" ],
"Organization": [ "GN", "SOUTHCOM", "UCMJ", "PRC" ],
"Date": [ "2016" ],
"People": [ "P.Walter" ]
}
{
"_id": 2,
"Record": 2,
"Link": [ "https://wikileaks.org/gifiles/docs/11/111533_-latam-centam-brief-110822-.html" ],
"Location": [ "NIC", "GTM", "JAM", "GTM", "PAN" ],
"Organization": [ "CENTAM", "Calibre Mining Corporation", "STRATFOR", "Alder Resources" ],
"Date": [ "2013" ],
"People": [ "Daniel Ortega", "Hugo Chavez", "Paulo Gregoire" ]
}
Basically, I'm trying to get an output like this :
{
"Country": "US",
"Years": [
{
"Year": "2016",
"Links": [ "https://wikileaks.org/gifiles/docs/11/111533_-latam-centam-brief-110822-.html",
"https://wikileaks.org/plusd/cables/1979PANAMA06344_e.html",
"https://wikileaks.org/gifiles/docs/90/9058_wax-12312008-csv-.html" ]
},
{
"Year": "2013",
"Links": [ ""https://wikileaks.org/gifiles/docs/11/111533_-latam-centam-brief-110822-.html",
"https://wikileaks.org/plusd/cables/1979PANAMA06344_e.html",
"https://wikileaks.org/gifiles/docs/90/9058_wax-12312008-csv-.html" ]
}
]
"Link_Count": 6
}
{
"Country": "UK",
"Years": [
{
"Year": "2009",
"Links": [ "https://wikileaks.org/gifiles/docs/11/111533_-latam-centam-brief-110822-.html",
"https://wikileaks.org/plusd/cables/1979PANAMA06344_e.html",
"https://wikileaks.org/gifiles/docs/90/9058_wax-12312008-csv-.html" ]
},
{
"Year": "2011",
"Links": [ ""https://wikileaks.org/gifiles/docs/11/111533_-latam-centam-brief-110822-.html",
"https://wikileaks.org/plusd/cables/1979PANAMA06344_e.html"]
}
]
"Link_Count": 5
}
I've tried to aggregate it, but I couldn't achieve what I want like I've given in the output. Here's my query :
db.test.aggregate([
{
"$unwind": "$Location"
},
{
"$group" : {
"_id": {
"Country": "$Location",
"Year": "$Date",
"Links": "$Link"
},
Loc: {
$addToSet: "$Location"
}
}
},
{
"$unwind": "$Loc"
},
{
"$group": {
"_id": "$Loc",
"Years": { "$push": {
"Year": "$_id.Year",
"Links": "$_id.Links"
}
}
}
}
]).toArray()
I used $unwind and $addToSet on $Location because there are duplicates found within $Location. I'm open to any suggestions or solution so please do tell! Thanks in advance!
You can use :
db.test.aggregate([{
"$unwind": "$Location"
}, {
"$unwind": "$Date"
}, {
"$unwind": "$Link"
}, {
"$group": {
"_id": {
"Country": "$Location",
"Year": "$Date"
},
Links: {
$addToSet: "$Link"
}
}
}, {
"$group": {
"_id": "$_id.Country",
Years: {
$push: {
"Year": "$_id.Year",
"Links": "$Links"
}
},
Link_Count: { $sum: { $size: "$Links" } }
}
}])
The idea is to $unwind all arrays to be able to $push link into a new array, and to count the grouped record with $size for the last $group stage.