How to aggregate in MongoDB using value inside array? - mongodb-query

I have a list of products in my collection like this:
[
{
"name": "product1",
"categories": [
{
"category": "Food",
"subcategory": "Nuts"
},
{
"category": "Candies",
"subcategory": "Chocolate"
}
]
},
{
"name": "product2",
"categories": [
{
"category": "Food",
"subcategory": "Nuts"
},
{
"category": "Candies",
"subcategory": "Mint"
}
]
},
{
"name": "product3",
"categories": [
{
"category": "Food",
"subcategory": "Cakes"
},
{
"category": "Pastries",
"subcategory": "Chocolate"
}
]
}
]
I want to get a count of products using aggregate. If I run
db.collection.aggregate([{ $group: { _id: "$categories", count: { $sum: 1 }} }])
I get this:
[
{
"_id": [{ "category": "Food", "subcategory": "Nuts" }, { "category": "Candies", "subcategory": "Chocolate" }],
"count": 1
},
{
"_id": [{ "category": "Food", "subcategory": "Nuts" }, { "category": "Candies", "subcategory": "Mint" }],
"count": 1
},
{
"_id": [{ "category": "Food", "subcategory": "Cakes" }, { "category": "Pastries", "subcategory": "Chocolate" }],
"count": 1
}
]
But what I really need is to find count per category and subcategory, like this:
[
{ "_id": { "category": "Food", "subcategory": "Nuts" }, "count": 2 },
{ "_id": { "category": "Food", "subcategory": "Cakes" }, "count": 1 },
{ "_id": { "category": "Candies", "subcategory": "Chocolate" }, "count": 1 },
{ "_id": { "category": "Candies", "subcategory": "Mint" }, "count": 1 },
{ "_id": { "category": "Pastries", "subcategory": "Chocolate" }, "count": 1 }
]
Is there a query to obtain this?

You have to $unwind categories first
db.collection.aggregate([
{
$unwind: "$categories"
},
{
$group: { _id: "$categories", count: { $sum: 1 } }
}
])

Related

how to solve this error in mongodb aggregation: TypeError: ({$unwind:{path:"$tags", preserveNullAndEmptyArrays:true}}) is not iterable :

i have a collection
[{
"_id": {"$oid": "63873b95c7e956270e734f3c"},
"employeeId": "emp1",
"users": [{"name": "Allen","registered": true},
{"name": "Henry","registered": true},
{"name": "Adam","registered": false}],
"tags": ["good","excellent","average"]
},{
"_id": {"$oid": "63873c05c7e956270e734f3d"},
"employeeId": "emp2",
"users": [{"name": "Federick","registered": false},
{"name": "Mary","registered": true},
{"name": "Sam","registered": false} ],
"tags": ["poor","excellent", "good"]}
,{
"_id": {"$oid": "63873c1fc7e956270e734f3e"},
"employeeId": "emp3",
"users": [ {"name": "john", "registered": true},
{"name": "jack","registered": true},
{"name": "elle", "registered": false } ],
"tags": ["very good", "excellent", "good" ]}]
i am trying to groupby tags and employee with count of employees under each tag,expected output is
i am getting the correct output by python code which is
pipeline = [{"$unwind":"$users"},{"$match":{"users.registered":True}},
{"$unwind":"$tags"},
{
"$group": {
"_id": "$tags","employees":{"$push": {"employeeId":"$employeeId"}},
"employees" : { "$addToSet" : "$employeeId" },
"count": {
"$sum": 1
}
}
},
{"$project":{"_id":1,"employees":1,"size":{"$size":"$employees"}}},
{"$sort" : { "size": -1 } },
]
rec = db.ratings.aggregate(pipeline)
but its giving error in mongoshell
Is this what you want?
db.collection.aggregate([
{
"$unwind": "$tags"
},
{
"$group": {
"_id": "$tags",
"employees": {
"$push": "$employeeId"
}
}
},
{
"$project": {
"_id": 1,
"employees": 1,
"size": {
"$size": "$employees"
}
}
},
{
"$sort": {
"size": -1
}
}
])
See how it works on the playground example

Shopware 6 API / Product Listing / How to add available color variants for each product on the response

API Request
/store-api/product-listing/{categoryId}
I want each product in the API response to have available color variants. Because I want to show color variants on the product list page. But currently this data is not provided by the shopware 6 api.
I've tried to add this data by using associations but it didnt help.
Request Body
{
"includes": {
"product": ["id", "productNumber", "cover", "options"]
},
"associations": {
"options": {
"media": []
}
}
}
The request body looks to be correct. If the product is a variant then it should have content for options.
To verify try the following request body:
{
"limit": 1,
"includes": {
"product": ["id", "productNumber", "options"],
"property_group_option": ["name", "group"],
"property_group": ["name"]
},
"associations": {
"options": {
"associations": {
"group": []
}
}
},
"filters": [
{
"type": "not",
"operator": "and",
"queries": [
{
"type": "equals",
"field": "parentId",
"value": null
}
]
}
]
}
This should yield a single variant.
Response should look similar to this:
{
"entity": "product",
"total": 1,
"aggregations": [],
"page": 1,
"limit": 1,
"elements": [
{
"productNumber": "10042.1",
"options": [
{
"name": "linen",
"group": {
"name": "textile",
"apiAlias": "property_group"
},
"apiAlias": "property_group_option"
},
{
"name": "35",
"group": {
"name": "size",
"apiAlias": "property_group"
},
"apiAlias": "property_group_option"
},
{
"name": "chartreuse",
"group": {
"name": "shirt-color",
"apiAlias": "property_group"
},
"apiAlias": "property_group_option"
}
],
"id": "0002ea44c49c41ecb91c43e7e49e422d",
"apiAlias": "product"
}
],
"states": [],
"apiAlias": "dal_entity_search_result"
}

Compare two structs in BigQuery recursively ignoring key order

Let's say I have a complex struct, perhaps with ten levels of nesting and repeated fields. Is there a built-in way to compare these two objects to see if they are the same minus the sorting of keys? This may be related to: Compare two json values for equality. An example might be:
{
"id": "0001",
"type": "donut",
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "type": "Powdered Sugar" , "id": "5007"},
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
],
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
}
}
Versus:
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "type": "None", "id": "5001" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
From the previous question, we learnt that JSON type allows such a comparison, then it is just a matter of how to use JSON type as a proxy to compare the 2 structs
with data as (
select struct<a string, b struct<x string, y string>>('a', ('x', 'y')) col1,
struct<b struct<y string, x string>, a string>(('y', 'x'), 'a') col2,
) select col1,
col2,
TO_JSON_STRING(PARSE_JSON(TO_JSON_STRING(col1))) = TO_JSON_STRING(PARSE_JSON(TO_JSON_STRING(col2)))
from data;

aggregate in mongodb left join with $lookup

I have three collections
posts=[
{
"id": "p1",
"title": "title 1"
},
{
"id": "p2",
"title": "title 2"
}]
users = [
{
"id": "u1",
"name": "name1"
},
{
"id": "u2",
"name": "name2"
}]
comments = [
{
"userId": "u1",
"postId": "p1",
"comment": "comment 1"
}]
I want to get all collection posts and comments in each post by userId(u1) as:
posts=[
{
"id": "p1",
"title": "title 1",
"comments":[
"userId": "u1",
"comment": "comment 1"
]
},
{
"id": "p2",
"title": "title 2",
"comments":[]
}]
I used aggregate function and $lookup operator but I don't know using the $match operator to filter userId. I used aggregate bellow:
self.db.posts.aggregate([
{
"$lookup":{
"from": "comments",
"localField": "id",
"foreignField": "postId",
"as": "comments",
}
},
{
"$match":{
"comments.userId": {"$eq": param.objectUserId}
},
},
{"$skip": (param.page - 1) * param.pageSize},
{"$limit": param.pageSize},
{"$sort": {"unixDate": pymongo.DESCENDING}}
])
It only return one post in array corresponding with userId="u1"
Please help me!
Thank all!
You have to make use of the pipeline option of $lookup stage and pass the additional conditions that you want to apply.
db.posts.aggregate([
{
"$lookup": {
"from": "comments",
"let": {
"pId": "$id"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$postId",
"$$pId"
],
},
"userId": "u1",
},
},
{
"$project": {
"_id": 0,
"userId": 1,
"comment": 1,
},
},
],
"as": "comments"
}
}
])
Mongo Playground Sample Execution
self.db.posts.aggregate([
{
"$lookup": {
"from": "comments",
"let": {
"pId": "$id"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$postId",
"$$pId"
],
},
"userId": param.objectUserId,
},
},
{
"$project": {
"_id": 0,
"userId": 1,
"comment": 1,
},
},
],
"as": "comments"
}
},
{"$skip": (param.page - 1) * param.pageSize},
{"$limit": param.pageSize},
{"$sort": {"unixDate": pymongo.DESCENDING}}
])

Problem to fetch data in api call in flutter/dart

how can I fetch the name and team_name keys in this API data?
condition: here 18,1,17, etc are subject codes that change according to the subject and not fix this subject available in the next API call.
{
"18": {
"detail": {
"id": "18",
"name": "Hindi"
},
"list": [
{
"id": "5",
"team_name": "Gurpreet",
},
{
"id": "2",
"team_name": "Test1",
}
]
},
"17": {
"detail": {
"id": "17",
"name": "Punjabi"
},
"list": [
{
"id": "6",
"team_name": "Guru",
},
{
"id": "3",
"team_name": "Test",
}
]
},
"1": {
"detail": {
"id": "1",
"name": "History"
},
"list": [
{
"id": "7",
"team_name": "Gurpreet",
}
]
},
"19": {
"detail": {
"id": "19",
"name": "Math"
},
"list": [
{
"id": "4",
"team_name": "Gurpreet",
}
]
},
"status": true
}
Use this code. You can check keys getter to check dynamics key.
import 'dart:convert';
void main() async {
var f = {
"18": {
"detail": {"id": "18", "name": "Hindi"},
"list": [
{
"id": "5",
"team_name": "Gurpreet",
},
{
"id": "2",
"team_name": "Test1",
}
]
},
"17": {
"detail": {"id": "17", "name": "Punjabi"},
"list": [
{
"id": "6",
"team_name": "Guru",
},
{
"id": "3",
"team_name": "Test",
}
]
},
"1": {
"detail": {"id": "1", "name": "History"},
"list": [
{
"id": "7",
"team_name": "Gurpreet",
}
]
},
"19": {
"detail": {"id": "19", "name": "Math"},
"list": [
{
"id": "4",
"team_name": "Gurpreet",
}
]
},
"status": true
};
for (var o in f.keys) {
print(o);
if (f[o] is bool) {
print(f[o]);
} else { // check it is Map. I consider it always is Map
if ((f[o] as Map)['detail'] != null) {
print((f[o] as Map)['detail']['name']);
}
if ((f[o] as Map)['list'] != null) {
print((f[o] as Map)['list'][0]['team_name']); // you can use for here. please check array is not null
}
}
}
}