MongoDB Generate Group query based on the keyword - mongodb

I am trying to create top 10 product list based on postType = "buy". My logic is a count postType = "buy" and sort the top 10 products from the logs collection. Here are my sample log collections.
[
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "3",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "view",
"product": "4",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "view",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "share",
"product": "3",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "share",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "1",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "1",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "viewvideo",
"product": "1",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "viewvideo",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "viewvideo",
"product": "3",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "4",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "5",
}
]
I am trying to get count for totalBuybutton, totalShareButton, totalView if 'buy' keyword matched.
My expected output is:
[
{"product":1, "totalBuycount":2, "shareButtonCount":4, viewCount":4},
{"product":2, "totalBuycount":3, shareButtonCount":4, viewCount":4},
{"product":3, "totalBuycount":1, shareButtonCount":4, viewCount":4},
{"product":4, "totalBuycount":1, shareButtonCount":4, viewCount":4},
{"product":5, "totalBuycount":1, shareButtonCount":2, viewCount":4}
]
My current implementation is as below
aggregate([
{
$match: {
postType: "buybutton"
},
},
{
$group: {
_id: "$product",
count: {
$count: {}
}
}
},
{
$project: {
product: "$_id",
count: 1,
_id: 0,
},
},)

No idea, if this is what you are looking for.
The main part is
{
$group: {
_id: { postType: "$postType", product: "$product" },
count: { $count: {} }
}
}
Do you really need exactly the output as given in the question. It would require quite a lot of cosmetic work
db.collection.aggregate([
{
$group: {
_id: { postType: "$postType", product: "$product" },
count: { $count: {} }
}
},
{
$group: {
_id: "$_id.product",
data: { $push: "$$ROOT" }
}
},
{
$project: {
_id: 0,
product: "$_id",
data: {
$arrayToObject: {
$map: {
input: "$data", in: {
k: "$$this._id.postType", v: "$$this.count",
}
}
}
}
}
},
{ $replaceWith: { $mergeObjects: ["$$ROOT", "$data"] } },
{ $unset: "data" }
])
]
{ product: '5', buy: 1 },
{ product: '3', buy: 1, share: 1, viewvideo: 1 },
{ product: '2', buy: 3, view: 1, viewvideo: 1, share: 1 },
{ product: '1', viewvideo: 1, buy: 2 },
{ product: '4', buy: 1, view: 1 }
]
Mongo Playground

Related

MongoDB group query based on input

I am trying to create top 10 product list based on postType = "buy". My logic is a count postType = "buy" and sort the top 10 products from the logs collection. Here are my sample log collections.
[
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "3",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "view",
"product": "4",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "view",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "share",
"product": "3",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "share",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "1",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "1",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "viewvideo",
"product": "1",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "viewvideo",
"product": "2",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "viewvideo",
"product": "3",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "4",
},
{
"_id": "633dc5b761ff04e7ae8e8c0f",
"postType": "buy",
"product": "5",
}
]
My expected output is:
[{"product":1, "count":2},{"product":2, "count":3},{"product":3, "count":1},
{"product":4, "count":1},{"product":5, "count":1}
]
I tried the following code, but it is not working.
{
$project: {
_id: 0,
list: { $setEquals: ["$postType", "buy"] }
}
}
I just inserted 4 products but it will be 10 actually.
Would be this one:
db.collection.aggregate([
{ $match: { postType: "buy" } }, // filter on postType = "buy"
{
$group: { // group and count
_id: "$product",
count: { $count: {} }
}
},
{
$project: { // some cosmetic
product: "$_id",
count: 1,
_id: 0
}
}
])
Mongo Playground

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

mongo aggregate group, match, project, count

I am trying to get an aggregate work in mongo
Here is a simple json structure, and how I would like to achieve the aggregate.
// this is the format of the collection
[
{
_id: 6154f64df41fa3628ac2062a,
type: 'email',
platform: 'google',
apiDataId: '17c33ac4735c80bf',
timestamp: '2021-09-01',
userId: '6132a04892559282c40fd29a',
groupId: '6132a0cb74af9d82df74e918',
__v: 0
},
{
_id: 6154f64df41fa3628ac2062b,
type: 'call',
platform: 'yahoo',
apiDataId: '17c2d25e2ccf770d',
timestamp: '2021-09-01',
userId: '6132a04892559282c40fd29a',
groupId: '6132a0cb74af9d82df74e918',
__v: 0
},
{
_id: 6154f64df41fa3628ac2062c,
type: 'email',
platform: 'google',
apiDataId: '2021-09-03',
timestamp: '1632958029720',
userId: '6132a04892559282c40ff2a9',
groupId: '6132a0cb74af9d82df74e918',
__v: 0
},
{
_id: 6154f64df41fa3628ac2062d,
type: 'email',
platform: 'google',
apiDataId: '17c273deffc51cc9',
timestamp: '2021-09-04',
userId: '6132a04892559282c40fd29a',
groupId: '6132a0cb74af9d82df74e918',
__v: 0
},
{
_id: 6154f64df41fa3628ac2062e,
type: 'call',
platform: 'yahoo',
apiDataId: '17c14c85f6a89088',
timestamp: '2021-09-04',
userId: '6132a04892559282c40ff2a9',
groupId: '6132a0cb74af9d82df74e918',
__v: 0
}
]
I've started out wrting the aggregate, but I am having hard time understanding the aggregate,
aggregate([
{ $match: { groupId: groupId } },
{ $group: { _id: "$userId" } },
{ $group: { timestamp: "$timestamp" } },
{ $project: { "groupId": 0, "userId": 0} },
{ $count: "num_data" }
]).exec()
what I am trying to accomplish edited
[
groupId: '6132a04892559282c40fd29a',
userId: {
calls: [
"2021-09-01": {platform: "yahoo"},
"2021-09-03": {platform: "yahoo"},
...
],
emails: [
"2021-09-01": {platform: "google"},
"2021-09-04": {platform: "google"},
...
],
},
userId: { ... }
]
of course that aggregation doesn't work, I am having hard time understanding and trying to figure out the orders and what $things to use.
Is this aggregate is what you looking for?
db.collection.aggregate([
{
$match: {
groupId: "1"
}
},
{
$group: {
_id: "$userId",
count: {
$sum: 1
},
apiDataId: {
"$first": "$$ROOT"
}
}
},
{
"$project": {
"count": "$count",
"apiDataId": {
"timestamp": "$apiDataId.timestamp",
"platform": "$apiDataId.platform",
"type": "$apiDataId.type",
"data": "$apiDataId.data"
}
}
}
])
data
[
{
"groupId": "1",
"timestamp": "1",
"userId": "1",
"platform": "1",
"apiDataId": "1",
"type": "1",
"data": "1"
},
{
"groupId": "1",
"timestamp": "1",
"userId": "2",
"platform": "3",
"apiDataId": "4",
"type": "5",
"data": "6"
},
{
"groupId": "1",
"timestamp": "3",
"userId": "2",
"platform": "7",
"apiDataId": "8",
"type": "9",
"data": "9"
},
{
"groupId": "2",
"timestamp": "1",
"userId": "1",
"platform": "1",
"apiDataId": "1",
"type": "1",
"data": "1"
}
]
result
[
{
"_id": "2",
"apiDataId": {
"data": "6",
"platform": "3",
"timestamp": "1",
"type": "5"
},
"count": 2
},
{
"_id": "1",
"apiDataId": {
"data": "1",
"platform": "1",
"timestamp": "1",
"type": "1"
},
"count": 1
}
]
mongoplayground
Update: 2021-10-03
aggregate by userid then by date
db.collection.aggregate([
{
$match: {
__v: 0
}
},
{
$group: {
_id: {
u: "$userId",
t: "$timestamp"
},
count: {
$sum: 1
},
"timestampList": {
"$push": "$$ROOT"
}
}
},
{
$group: {
_id: "$_id.u",
count: {
$sum: 1
},
"userList": {
"$push": "$$ROOT"
}
}
}
])

MongoDB Aggregate and Group by Subcategories of products

I have a MongoDB schema that looks like this
const ProductModel = new Schema({
subcategory: {
type : mongoose.Schema.Types.ObjectId,
ref : "Subcategory",
},
product_name: {
type: String
},
description: {
type: String
},
price: {
type: Number
},
});
And a subcategory schema:
const SubcategoryModel = new Schema({
subcategoryName: {
type: String,
}
});
The input query before aggregation looks like this:
[
{
"_id": "111",
"subcategory": {
"_id": "456",
"categoryName": "Sneakers",
},
"product_name": "Modern sneaker",
"description": "Stylish",
"price": 4400
},
{
"_id": "222",
"subcategory": {
"_id": "456",
"categoryName": "Sneakers",
},
"product_name": "Blue shoes",
"description": "Vived colors",
"price": 7500
},
{
"_id": "333",
"subcategory": {
"_id": "123",
"categoryName": "Jackets",
"__v": 0
},
"product_name": "Modern jacket",
"description": "Stylish",
"price": 4400
},
}
]
The final result of the query should look like this:
{
"Sneakers":[
{
"product_name":"Modern sneaker",
"description":"Stylish",
"price":"4400"
},
{
"product_name":"Blue shoes",
"description":"Vived colors",
"price":"7500"
},
"Jackets":{
"...."
}
]
}
Subcategory before aggregation:
"subcategories": [
{
"_id": "123",
"categoryName": "Jackets",
},
{
"_id": "456",
"categoryName": "Sneakers",
}
]
I'm trying to populate the subcategory, And then group the products by their subcategoryName field.
You can use this aggregation query:
First $lookup to do the join between Product and Subcategory creating the array subcategories.
Then deconstructs the array using $unwind.
$group by the name of subproduct adding the entire object using $$ROOT.
The passes the fields you want using $project.
And replaceRoot to get key value into arrays as Sneakers and Jackets.
db.Product.aggregate([
{
"$lookup": {
"from": "Subcategory",
"localField": "subcategory.categoryName",
"foreignField": "categoryName",
"as": "subcategories"
}
},
{
"$unwind": "$subcategories"
},
{
"$group": {
"_id": "$subcategories.categoryName",
"data": {
"$push": "$$ROOT"
}
}
},
{
"$project": {
"data": {
"product_name": 1,
"description": 1,
"price": 1
}
}
},
{
"$replaceRoot": {
"newRoot": {
"$arrayToObject": [
[
{
"k": "$_id",
"v": "$data"
}
]
]
}
}
}
])
Example here
With your provided data, result is:
[
{
"Sneakers": [
{
"description": "Stylish",
"price": 4400,
"product_name": "Modern sneaker"
},
{
"description": "Vived colors",
"price": 7500,
"product_name": "Blue shoes"
}
]
},
{
"Jackets": [
{
"description": "Stylish",
"price": 4400,
"product_name": "Modern jacket"
}
]
}
]

MongoDB inner join with specific condition from both collections

I have got two collections, chapters and courses with one-to-one association,
db={
"chapters": [
{
"_id": 10,
"course_id": 1,
"author": "John"
},
{
"_id": 20,
"course_id": 2,
"author": "John"
},
{
"_id": 30,
"course_id": 3,
"author": "Timmy"
},
{
"_id": 40,
"course_id": 4,
"author": "John"
},
],
"courses": [
{
"_id": 1,
"published": true,
"name": "course 1"
},
{
"_id": 2,
"published": false,
"name": "course 2"
},
{
"_id": 3,
"published": true,
"name": "course 3"
},
{
"_id": 4,
"published": true,
"name": "course 4"
}
]
}
How do I query all chapters with the published course (published=true) and the author is "John"?
You can use $match, $lookup then $group by author then simply $filter it based on published
db.chapters.aggregate([
{
$match: {
author: "John"
}
},
{
"$lookup": {
"from": "courses",
"localField": "course_id",
"foreignField": "_id",
"as": "course"
}
},
{
$project: {
_id: 1,
course: {
$first: "$course"
},
author: 1
}
},
{
$group: {
_id: "$author",
courseChapters: {
$push: "$$ROOT"
}
}
},
{
$project: {
courseChapters: {
$filter: {
input: "$courseChapters",
as: "cc",
cond: {
$eq: [
"$$cc.course.published",
true
]
}
}
}
}
}
])
Output
[
{
"_id": "John",
"courseChapters": [
{
"_id": 10,
"author": "John",
"course": {
"_id": 1,
"name": "course 1",
"published": true
}
},
{
"_id": 40,
"author": "John",
"course": {
"_id": 4,
"name": "course 4",
"published": true
}
}
]
}
]
Mongoplayground: https://mongoplayground.net/p/x-XghXzZUk4