Get key value pair result of activities in Mongodb - mongodb

Get key value pair result of activities. get all activities under first elements term as key.
INPUT
[
{
"_id": "diamond",
"activities": [
[
{
"term": "11",
"sport_name": "football"
}
]
]
},
{
"_id": "topaz",
"activities": [
[
{
"term": "12",
"sport_name": "football"
}
],
[
{
"term": "11",
"sport_name": "football"
},
{
"term": "11",
"sport_name": "hand ball"
}
]
]
}
]
OUTPUT
[
{
"_id": "diamond",
"activities": [
{
"11": [
{
"term": "11",
"sport_name": "football"
}
]
}
]
},
{
"_id": "topaz",
"activities": [
{
"12": [
{
"term": "12",
"sport_name": "football"
}
]
},
{
"11": [
{
"term": "11",
"sport_name": "football"
},
{
"term": "11",
"sport_name": "hand ball"
}
]
}
]
}
]

You can use below aggregation
db.collection.aggregate([
{ "$project": {
"activities": {
"$arrayToObject": {
"$map": {
"input": "$activities",
"in": {
"k": { "$arrayElemAt": ["$$this.term", 0] },
"v": "$$this"
}
}
}
}
}}
])
MongoPlayground

Related

Get previous and next inside sub array in MongoDB

I have a database as below.
[
{
"title": "Data 1",
"slug": "data-1",
"sub_docs": [
{
"name": "Sub Doc 1",
"sub_slug": "sub-doc-1",
"urls": [
"https://example.com/path-1",
]
},
{
"name": "Sub Doc 2",
"sub_slug": "sub-doc-2",
"urls": [
"https://example.com/path-2"
]
},
{
"name": "Sub Doc 3",
"sub_slug": "sub-doc-3",
"urls": [
"https://example.com/path-3",
]
}
]
}
]
When I give data-1 and sub-doc-2 as input, I want to get the following result.
{
"title": "Data 1",
"sub_doc_title": "Sub Doc 2",
"urls": [
"https://example.com/path-2"
],
"prev": {
"name": "Sub Doc 1",
"sub_slug": "sub-doc-1"
},
"next": {
"name": "Sub Doc 3",
"sub_slug": "sub-doc-3"
}
}
I'm a bit of a beginner at MongoDB.
How can I do this query? Do you have an idea?
That's a tough query for beginner, although I still consider myself a novice so maybe there's a better/easy way.
Here's one way you could do it.
db.collection.aggregate([
{
"$match": {
"slug": "data-1" // given argument
}
},
{
"$set": {
"reduceOut": {
"$reduce": {
"input": "$sub_docs",
"initialValue": {
"sub_doc_title": null,
"urls": [],
"prev": null,
"next": null
},
"in": {
"$cond": [
{
"$eq": [
"$$this.sub_slug",
"sub-doc-2" // given argument
]
},
{
"$mergeObjects": [
"$$value",
{
"sub_doc_title": "$$this.name",
"urls": "$$this.urls"
}
]
},
{
"$cond": [
{ "$eq": [ "$$value.sub_doc_title", null ] },
{
"$mergeObjects": [
"$$value",
{
"prev": {
"name": "$$this.name",
"sub_slug": "$$this.sub_slug"
}
}
]
},
{
"$cond": [
{ "$eq": [ "$$value.next", null ] },
{
"$mergeObjects": [
"$$value",
{
"next": {
"name": "$$this.name",
"sub_slug": "$$this.sub_slug"
}
}
]
},
"$$value"
]
}
]
}
]
}
}
}
}
},
{
"$replaceWith": {
"$mergeObjects": [
{
"title": "$title"
},
"$reduceOut"
]
}
}
])
Try it on mongoplayground.net.
Thanks rickhg12hs for your answer. I also found a solution to this question.
Here is my answer;
db.collection.aggregate([
{
"$match": {
"slug": "data-1"
}
},
{
"$addFields": {
"sub_doc_index": {
"$indexOfArray": [
"$sub_docs.sub_slug",
"sub-doc-2"
]
}
}
},
{
"$project": {
"title": 1,
"sub_doc_title": {
"$arrayElemAt": [
"$sub_docs.name",
"$sub_doc_index"
]
},
"urls": {
"$arrayElemAt": [
"$sub_docs.urls",
"$sub_doc_index"
]
},
"prev": {
"$cond": {
"if": {
"$eq": [
{
"$subtract": [
"$sub_doc_index",
1
]
},
-1
]
},
"then": {},
"else": {
"name": {
"$arrayElemAt": [
"$sub_docs.name",
{
"$subtract": [
"$sub_doc_index",
1
]
}
]
},
"slug": {
"$arrayElemAt": [
"$sub_docs.sub_slug",
{
"$subtract": [
"$sub_doc_index",
1
]
}
]
}
},
},
},
"next": {
"name": {
"$arrayElemAt": [
"$sub_docs.name",
{
"$add": [
"$sub_doc_index",
1
]
}
]
},
"slug": {
"$arrayElemAt": [
"$sub_docs.sub_slug",
{
"$add": [
"$sub_doc_index",
1
]
}
]
}
}
}
},
])

Mongodb: How to merge $facet output 2 by 2?

Playground:https://mongoplayground.net/p/YUV_fReyGsr
I have following query. I need to combine the result 2 by 2. Meaning I need to combine facet "1","2" as a result and facet "3","4" as another result. It's guaranteed that the number of facet will be even. Also, each pair of facet should get at most one record(it might not matter)
db.collection.aggregate([
{
"$facet": {
"1": [
{
$match: {
"ID": "2"
}
}
],
"2": [
{
$match: {
"array.ID": "2"
}
}
],
"3": [
{
$match: {
"array.ID": "4"
}
}
],
"4": [
{
$match: {
"ID": "4"
}
}
]
}
}
])
The expected result will be
[
{
"1": [
{
"ID": "1",
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
],
"attr1": "123"
}
],
"2": [
{
"ID": "4",
"array": [
{
"ID": "5",
"attr1": "456"
}
],
"attr1": "123"
}
]
}
]
I was able to figure this out using $concatArrays operator, along with $project.
Live demo here
Database
[
{
"ID": "1",
"attr1": "123",
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
]
},
{
"ID": "4",
"attr1": "123",
"array": [
{
"ID": "5",
"attr1": "456"
}
]
}
]
Query
db.collection.aggregate([
{
"$facet": {
"1": [
{
$match: {
"ID": "2"
}
}
],
"2": [
{
$match: {
"array.ID": "2"
}
}
],
"3": [
{
$match: {
"array.ID": "4"
}
}
],
"4": [
{
$match: {
"ID": "4"
}
}
]
}
},
{
"$project": {
_id: 0,
"1": {
"$concatArrays": [
"$1",
"$2"
]
},
"2": {
"$concatArrays": [
"$3",
"$4"
]
}
}
}
])
Result
[
{
"1": [
{
"ID": "1",
"_id": ObjectId("5a934e000102030405000000"),
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
],
"attr1": "123"
}
],
"2": [
{
"ID": "4",
"_id": ObjectId("5a934e000102030405000001"),
"array": [
{
"ID": "5",
"attr1": "456"
}
],
"attr1": "123"
}
]
}
]

Get the $size (length) of a nested array and calculate the difference to a stored value on the parent object - using aggregate

Let's consider that I have the following documents (ignoring the _id):
[
{
"Id": "Store1",
"Info": {
"Location": "Store1 Street",
"PhoneNumber": 111
},
"MaxItemsPerShelf": 3,
"Shelf": [
{
"Id": "Shelf1",
"Items": [
{
"Id": "Item1",
"Name": "bananas"
},
{
"Id": "Item2",
"Name": "apples"
},
{
"Id": "Item3",
"Name": "oranges"
}
]
},
{
"Id": "Shelf2",
"Items": [
{
"Id": "Item4",
"Name": "cookies"
},
{
"Id": "Item5",
"Name": "chocolate"
}
]
},
{
"Id": "Shelf3",
"Items": []
}
]
},
{
"Id": "Store3",
"Info": {
"Location": "Store2 Street",
"PhoneNumber": 222
},
"MaxItemsPerShelf": 2,
"Shelf": [
{
"Id": "Shelf4",
"Items": [
{
"Id": "Item6",
"Name": "champoo"
},
{
"Id": "Item7",
"Name": "toothpaste"
}
]
},
{
"Id": "Shelf5",
"Items": [
{
"Id": "Item8",
"Name": "chicken"
}
]
}
]
}
]
Given a specific Shelf.Id I want to get the following result ( Shelf.Id = "Shelf2"):
[{
"Info": {
"Location": "Store1 Street",
"PhoneNumber": 111
},
"ItemsNumber": 2,
"ItemsRemaining": 1
}]
Therefore:
ItemsNumberis the $size of Shelf
and
ItemsRemainingis equal to MaxItemsPerShelf $size of Shelf
also I want to copy the value of the Info to the aggregate output.
How can I accomplish this with aggregate? On my efforts I couldn't pass through an iterator that gets the $size of $Shelf.Items
You can use below aggregation
db.collection.aggregate([
{ "$match": { "Shelf.Id": "Shelf2" }},
{ "$replaceRoot": {
"newRoot": {
"$let": {
"vars": {
"shelf": {
"$filter": {
"input": {
"$map": {
"input": "$Shelf",
"in": {
"Id": "$$this.Id",
"count": { "$size": "$$this.Items" }
}
}
},
"as": "ss",
"cond": { "$eq": ["$$ss.Id", "Shelf2"] }
}
}
},
"in": {
"Info": "$Info",
"ItemsNumber": { "$arrayElemAt": ["$$shelf.count", 0] },
"ItemsRemaining": {
"$subtract": [
"$MaxItemsPerShelf",
{ "$ifNull": [
{ "$arrayElemAt": ["$$shelf.count", 0] },
0
]}
]
}
}
}
}
}}
])

Filter by nested arrays/objects values (on different levels) and $project by matching groups (on a specific level) - MongoDB Aggregate

Considering I have the following collection (ignoring documents _id):
Collection
[
{
"Id": "1",
"Level2": [
{
"Id": "1.1",
"Level3": [
{
"Id": "1.1.1",
"Level4": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
]
},
{
"Id": "1.1.2",
"Level4": [
{
"Id": "1.1.2.1",
"Status": "a"
},
{
"Id": "1.1.2.2",
"Status": "c"
}
]
},
{
"Id": "1.1.3",
"Level4": [
{
"Id": "1.1.3.1",
"Status": "c"
}
]
}
]
}
]
},
{
"Id": "2",
"Level2": [
{
"Id": "2.1",
"Level3": [
{
"Id": "2.1.1",
"Level4": [
{
"Id": "2.1.1.1",
"Status": "a"
}
]
}
]
}
]
}
]
Conditions
I want to query it such as:
Level2.Id: "1.1"
Level2.Level3.Level4.Status $in ["a", "b"]
The $project should:
Group Level2.Level3.Level4 matches by Level2.Level3
Should not include Level2.Level3 if it is an empty array
The expected result should be:
Result 1
[
{
"Id": "1.1.1",
"Level4": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
]
},
{
"Id": "1.1.2",
"Level4": [
{
"Id": "1.1.2.1",
"Status": "a"
}
]
}
]
Please notice that if current Level2.Id: "2.1" has the value "1.1" instead, the result should be (matches on different documents):
Result 2
[
{
"Id": "1.1.1",
"Level4": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
]
},
{
"Id": "1.1.2",
"Level4": [
{
"Id": "1.1.2.1",
"Status": "a"
}
]
},
{
"Id": "2.1.1",
"Level4": [
{
"Id": "2.1.1.1",
"Status": "a"
}
]
}
]
How can I accomplish this with an aggregate query?
( filtering different levels and grouping by some level )
Here it is the answer (thank you to #Vijay Rajpurohit for his help on this):
db.collection.aggregate([
{
$unwind: "$Level2"
},
{
$unwind: "$Level2.Level3"
},
{
$unwind: "$Level2.Level3.Level4"
},
{
$match: {
"Level2.Id": "1.1",
"Level2.Level3.Level4.Status": {
$in: [
"a",
"b"
]
}
}
},
{
$group: {
"_id": "$Level2.Level3.Id",
"Messages": {
$push: "$Level2.Level3.Level4"
}
}
}
])
The result of this query is:
[
{
"Messages": [
{
"Id": "1.1.2.1",
"Status": "a"
}
],
"_id": "1.1.2"
},
{
"Messages": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
],
"_id": "1.1.1"
}
]
Mongo Playground

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"
}}
])