mongodb: How to build facets from an array of objects - mongodb

What would be the best way to create facets from an array of objects with different attributes for each product.
Example Data:
[
{
"key": 1,
"title": "Product A",
"attrs": [
{
"keyasd": "size",
"value": "small"
},
{
"kedasy": "color",
"value": "red"
}
]
},
{
"key": 2,
"title": "Product B",
"attrs": [
{
"key": "size",
"value": "large"
},
{
"key": "color",
"value": "blue"
}
]
},
{
"key": 3,
"title": "Product C",
"attrs": [
{
"key": "resolution",
"value": "8K"
},
{
"key": "refresh rate",
"value": "60 Hz"
},
]
}
]
The result I would like to get would be something like this:
[
{
"_id": {
"key": "size",
"values" : [
{"title": "small", "count": 1},
{"title": "large", "count": 1}
]
}
},
{
"_id": {
"key": "color",
"values" : [
{"title": "red", "count": 1},
{"title": "blue", "count": 1}
]
}
},
{
"_id": {
"key": "resolution",
"values" : [
{"title": "8K", "count": 1}
]
}
},
{
"_id": {
"key": "refresh rate",
"values" : [
{"title": "60 Hz", "count": 1}
]
}
}
]
I don't know if the result I put is possible, but I need to somehow build it, even if it's individually each facet for each type of attribute that a product can have

db.collection.aggregate([
{
"$unwind": "$attrs"
},
{
"$group": {
"_id": {
k: "$attrs.key",
v: "$attrs.value"
},
"count": { "$sum": 1 }
}
},
{
"$group": {
"_id": "$_id.k",
"values": {
"$push": {
"title": "$_id.v",
"count": "$count"
}
}
}
},
{
"$project": {
"_id": {
key: "$_id",
values: "$values"
}
}
}
])
mongoplayground

Related

Aggregate occurrences of events in nested array

Given the following input:
[
{
"statuses": [
{
"status": "allowed",
"count": 3,
"events_count": [
"2001",
"1001",
"1001"
]
}
],
"date": "2022-09-10 15:00",
"_id": "2022-09-10 15:00"
}
]
I need count the number of occurrences of stauses.events_count, so the output would be:
[
{
"statuses": [
{
"status": "allowed",
"count": 3,
"events_count": [
{"type": "2001", "count": 1},
{"type": "1001", "count": 2},
]
}
],
"date": "2022-09-10 15:00",
"_id": "2022-09-10 15:00"
}
]
What I've tried
This is what I got so far:
db.collection.aggregate([
{
"$unwind": "$statuses"
},
{
"$unwind": "$statuses.events_count"
},
{
"$group": {
"_id": {
"event_count": "$statuses.events_count",
"status": "$statuses.status",
"date": "$date",
"count": "$statuses.count"
},
"occurences": {
"$sum": 1
}
}
}
])
Which produces:
[
{
"_id": {
"count": 3,
"date": "2022-09-10 15:00",
"event_count": "2001",
"status": "allowed"
},
"occurences": 1
},
{
"_id": {
"count": 3,
"date": "2022-09-10 15:00",
"event_count": "1001",
"status": "allowed"
},
"occurences": 2
}
]
I'm having difficulties grouping everything back together. I tried grouping by date and pushing back to a 'statuses' array, but it produces two items in the array (with status==allowed), rather than 1 item with status==allowed
You did 2 $unwinds, so it should be 2 $groups in reverse order:
{
"$group": {
"_id": {
"status": "$_id.status",
"count": "$_id.count",
"date": "$_id.date"
},
"event_count": {
"$push": {
"type": "$_id.event_count",
"count": "$occurences"
}
}
}
},
{
"$group": {
"_id": "$_id.date",
"date": {"$last": "$_id.date"},
"statuses": {
"$push": {
"status": "$_id.status",
"count": "$_id.count",
"event_count": "$event_count"
}
}
}
}

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

MongoDB, How to associate array fields for statistics

Example JSON:
{
"groups": [
{
"_id": 1,
"name": "g1"
},
{
"_id": 2,
"name": "g2"
}
],
"items": [
{
"_id": 1,
"name": "item1",
"gid": 1
},
{
"_id": 2,
"name": "item2",
"gid": 2
}
]
}
How to associate two arrays and count ?I tried to use aggregate, I didn't get the results I wanted.
Required Result:
Or can directly find all the items associated with it, perfect....
{"groups": [
{
"_id": 1,
"name": "g1",
"count": 1,
"items": [
{
"_id": 1,
"name": "item1"
}
]
},
{
"_id": 2,
"name": "g2",
"count": 1,
"items": [
{
"_id": 2,
"name": "item2"
}
]
}
]}
db.getCollection('collection').aggregate([
{$unwind:{
path:"$groups",
preserveNullAndEmptyArrays:true
}},
{$unwind:{
path:"$items",
preserveNullAndEmptyArrays:true
}},
{$redact: {$cond: [{
$eq: [
"$groups._id",
"$items.gid"
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{$project:{
_id:1,
groups_id:"$groups._id",
group_name:"$groups.name",
item_data:{
_id:"$items._id",
name:"$items.name",
}
}},
{
$group:{
_id:"$groups_id",
name:{$first:"$group_name"},
count:{$sum:1},
items:{$push:"$item_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, grouping inner Hash key value by another key value

I have these 4 elements in my collection:
/* 1 */
{
"demographics": [
{
"key": "country",
"value": "ES"
},
{
"key": "city",
"value": "Sevilla"
},
{
"key": "region",
"value": "Andalucía"
}
]
}
/* 2 */
{
"demographics": [
{
"key": "city",
"value": "Cádiz"
},
{
"key": "country",
"value": "ES"
},
{
"key": "region",
"value": "Andalucía"
}
]
}
/* 3 */
{
"demographics": [
{
"key": "country",
"value": "GB"
},
{
"key": "region",
"value": "Greater London"
},
{
"key": "city",
"value": "London"
}
]
}
/* 4 */
{
"demographics": [
{
"key": "country",
"value": "ES"
},
{
"key": "region",
"value": "Andalucía"
},
{
"key": "city",
"value": "Sevilla"
}
]
}
I would like to group them by:
demographic.value when demographic.key = "country"
demographic.value when demographic.key = "region"
demographic.value when demographic.key = "city"
Having a result like this:
{ "values": ["ES", "Andalucía", "Sevilla"], "count": 2 }
{ "values": ["ES", "Andalucía", "Cádiz"], "count": 1 }
{ "values": ["GB", "Greater London", "London"], "count": 1 }
Attention: beware the order of the demographics array elements might be not always the same.
I have tried
db.getCollection('test').aggregate(
[
{ "$unwind": "$demographics" },
{
"$project" :{
"_id": 0,
"demographics.key": 1,
"demographics.value": 1
}
},
{
"$group" : {
"_id": {
"key": "$demographics.key",
"value": "$demographics.value"
},
"count": { "$sum": 1 }
}
},
{
"$group" : {
"_id": "$_id.key",
"values": { "$push": { "value": "$_id.value", "count": "$count" } }
}
}
]
)
This gives me this result:
/* 1 */
{
"_id": "country",
"values": [
{
"value": "GB",
"count": 1.0
},
{
"value": "ES",
"count": 3.0
}
]
}
/* 2 */
{
"_id": "region",
"values": [
{
"value": "Greater London",
"count": 1.0
},
{
"value": "Andalucía",
"count": 3.0
}
]
}
/* 3 */
{
"_id": "city",
"values": [
{
"value": "London",
"count": 1.0
},
{
"value": "Cádiz",
"count": 1.0
},
{
"value": "Sevilla",
"count": 2.0
}
]
}
But this is not the groups I am looking for
You can try running the following pipeline:
db.test.aggregate([
{ "$unwind": "$demographics" },
{ "$sort": { "demographics.key": 1, "demographics.value": 1 } },
{
"$group": {
"_id": "$_id",
"values": { "$push": "$demographics.value" }
}
},
{
"$group": {
"_id": "$values",
"count": { "$sum": 1 }
}
},
{
"$project": {
"_id": 0, "values": "$_id", "count": 1
}
}
])
Sample Output
/* 1 */
{
"count" : 2,
"values" : [
"Sevilla",
"ES",
"Andalucía"
]
}
/* 2 */
{
"count" : 1,
"values" : [
"London",
"GB",
"Greater London"
]
}
/* 3 */
{
"count" : 1,
"values" : [
"Cádiz",
"ES",
"Andalucía"
]
}