push group result into array mongodb - mongodb

I have this query in mongodb:
db.getCollection('users').aggregate([
{
$group: {
_id: "$type",
// items: { $push: "$_id.type" }
// items: { $addToSet: "$_id.type" }
}
},
{
$project: {
_id: 0,
type: "$_id",
}
}
]).toArray()
This will return a list like this:
[ {type: "AAA"}, {type: "BBB"}, {type: "CCC"} ]
But can I get something like this: ["AAA", "BBB", "CCC"]? Tried with $push and $addToSet but no result. Thank you for your time!
Later edit:
You can find an example here:
https://mongoplayground.net/p/-n0o5i6CnLq

Like this?
{
$group: {
_id: null,
type: {
$push: "$type"
}
}
},
{
$project: {
_id: 0,
type: 1
}
}

Try this one:
db.collection.aggregate([
{
$group: {
_id: null,
type: {
"$addToSet": "$type"
}
}
}
])

Related

Unable to sort documents after grouping mongodb aggregation framework

so i am trying to sort notifications array of user by it's insertion date (i want the latest one on top) but it seems to be not working am i missing something ?
here's the template for data:
{
_id: "628ceeae3df06d49419f0bb4",
name: "John",
notifications: [
{_id: "someIdA", details: "xyz", dateTime: "1653321337762"},
{_id: "someIdB", details: "jkl", dateTime: "1653321337762"}
{_id: "someIdC", details: "abc", dateTime: "1653321321323"}
{_id: "someIdD", details: "lmn", dateTime: "1653123412341"}
]
}
and the aggregation pipeline that i'm trying:
const foundUser = await users.aggregate([
{
$match: {
_id: mongoose.Types.ObjectId(userId)
}
},
{
$project: {
notifications: 1,
_id: 0
}
},
{
$sort: {
_id: -1
}
}
])
First unwind the array of notifications array, sort the documents by notifications DateTime key, then group them by the user.
This is the mongo shell query:
db.collection.aggregate([
{
$match: {
_id: "628ceeae3df06d49419f0bb4"
}
},
{
$unwind: "$notifications"
},
{
$sort: {
"notifications.dateTime": -1
}
},
{
$group: {
_id: "$_id",
notifications: {
$push: "$notifications"
}
}
},
{
"$project": {
"notifications": 1,
"_id": 0
}
}
])
Here, is the working link Mongodb Playground

MongoDB get size of unwinded array

I'm trying to return size of 'orders' and sum of 'item' values for each 'order' for each order from documents like the example document:
orders: [
{
order_id: 1,
items: [
{
item_id: 1,
value:100
},
{
item_id: 2,
value:200
}
]
},
{
order_id: 2,
items: [
{
item_id: 3,
value:300
},
{
item_id: 4,
value:400
}
]
}
]
I'm using following aggregation to return them, everything works fine except I can't get size of 'orders' array because after unwind, 'orders' array is turned into an object and I can't call $size on it since it is an object now.
db.users.aggregate([
{
$unwind: "$orders"
},
{
$project: {
_id: 0,
total_values: {
$reduce: {
input: "$orders.items",
initialValue: 0,
in: { $add: ["$$value", "$$this.value"] }
}
},
order_count: {$size: '$orders'}, //I get 'The argument to $size must be an array, but was of type: object' error
}
},
])
the result I expected is:
{order_count:2, total_values:1000} //For example document
{order_count:3, total_values:1500}
{order_count:5, total_values:2500}
I found a way to get the results that I wanted. Here is the code
db.users.aggregate([
{
$project: {
_id: 1, orders: 1, order_count: { $size: '$orders' }
}
},
{ $unwind: '$orders' },
{
$project: {
_id: '$_id', items: '$orders.items', order_count: '$order_count'
}
},
{ $unwind: '$items' },
{
$project: {
_id: '$_id', sum: { $sum: '$items.value' }, order_count: '$order_count'
}
},
{
$group: {
_id: { _id: '$_id', order_count: '$order_count' }, total_values: { $sum: '$sum' }
}
},
])
output:
{ _id: { _id: ObjectId("5dffc33002ef525620ef09f1"), order_count: 2 }, total_values: 1000 }
{ _id: { _id: ObjectId("5dffc33002ef525620ef09f2"), order_count: 3 }, total_values: 1500 }

How to aggregate to have the _id as a object property

I have the following collection:
{
_id: 1,
type: "Feature",
properties: {
name: "Name 1",
<other properties here>
}
},
{
_id: 2,
type: "Feature",
properties: {
name: "Name 2",
<other properties here>
}
}
How can I write a MongoDB Aggregate query to return the following ?
{
data: {
type: "Feature",
properties: {
_id: 1,
name: "Name 1",
<other properties here>
}
}
},
{
data: {
type: "Feature",
properties: {
_id: 2,
name: "Name 2",
<other properties here>
}
}
}
So, the _id should become an attribute of properties and each document should be returned as an object of data.
Simple structure manipulation will suffice:
db.collection.aggregate([
{
$project: {
data: {
type: "$type",
properties: {
$mergeObjects: [
{_id: "$_id"},
"$properties"
]
}
}
}
}
])
try this
1- If you need only the _id to be inside the properties, and not in data object
db.collection.aggregate([
{
$group: {
_id: "$_id",
type: {
$first: "$type"
},
properties: {
$first: {
_id: "$_id",
name: "$properties.name"
}
}
}
},
{
$project: {
_id: 0,
data: "$$ROOT"
}
},
{
$project: {
"data._id": 0
}
}
])
check this Mongo Playground
2- If it's matter only to get the _id inside the the properties object, and you don't care if it's in data or not
you can use this
db.collection.aggregate([
{
$group: {
_id: "$_id",
type: {
$first: "$type"
},
properties: {
$first: {
_id: "$_id",
name: "$properties.name"
}
}
}
},
{
$project: {
_id: 0,
data: "$$ROOT"
}
}
])
check this Mongo Playground 2
I was unable to utilize your dataset as it was not RFC 8259 formatted.
However assuming your dataset is properly formatted like below. The issued command would be near close provided the fields matched
{
"data":{
"Feature":{
"properties":{
"_id1":[
"object_of_data1",
"object_of_data2",
"object_of_data3"
],
"_id2":[
"object_of_data1",
"object_of_data2",
"object_of_data3"
],
"_id3":[
"object_of_data1",
"object_of_data2",
"object_of_data3"
]
}
}
}
}
I would then use the command:
db.orders.aggregate([
{ $match: { properties: "_id1" } },
{ $group: { _id1: "object_of_data1", "object_of_data2"
"object_of_data3" } } }
])
For further reading please see: Aggregation Commands Comparison

aggregation on replies and comments with same user in mongodb

Imagine we have the structure like the following:
comments: [{
user: '...',
upVotes: 12,
text: '...'
replies: [{
user: '...',
upVotes: 34,
text: '...'
}]
}]
what we want is to retrieve the user and text of comments and replies with the same user!
I have implemented the following query but it doesn't work:
db.getCollection('links').aggregate([
{
$unwind: "$comments"
},
{
$unwind: "$comments.replies"
},
{
$project: {
sameAuthor: {
$eq: ["$comments.user", "$comments.replies.user"]
},
}
}
])
I don't know where the problem is!
If you need more clear result please add result sample in the comment.
db.links.aggregate([
{ $unwind: '$comments'},
{ $unwind: '$comments.replies'},
{ $match: { $expr: { $eq: ["$comments.user", "$comments.replies.user"] } } },
{ $group: {
_id: '$_id',
user: { $first: "$comments.user" },
commentText: { $first: "$comments.text" },
repliesTaxt: { $push: "$comments.replies.text" }
}
}
])

MongoDB - Help needed to make some aggregation

I am having a bad time trying to do an aggregation in MongoDB.
I need to cross some infos from each user and as a final result I want a list of users (where there is only one object for each user) and for each object there is some lists with distinct information.
1 - The createdAtList array must be ordered from the oldest to the newest date. The sumOfTotal means the current position total summed up with the previous sumOfTotal (Exemplified in the code below), not just the sum of the total's
2 - The categotyList must be ordered like: category1, category2, category3 ...
3 - The desired final result must be ordered like: user1, user2, user3 ...
Basically I need some help to do the following:
//List of docs from my collection:
[
{
_id: "doc1",
user: "user1",
category: "category1",
createdAt: "2018-01-01T00:00:00.000Z"
},
{
_id: "doc2",
user: "user1",
category: "category2",
createdAt: "2017-12-12T00:00:00.000Z",
},
{
_id: "doc3",
user: "user1",
category: "category1",
createdAt: "2017-12-12T00:00:00.000Z",
},
{
_id: "doc4",
user: "user1",
category: "category2",
createdAt: "2018-01-01T00:00:00.000Z"
},
{
_id: "doc5",
user: "user1",
category: "category3",
createdAt: "2017-11-11T00:00:00.000Z"
}
]
//Desired result:
{
user: "user1",
createdAtList: [ //list ordered by createdAt
{
createdAt: "2017-11-11T00:00:00.000Z",
total: 1,
sumOfTotal: 0
}
{
createdAt: "2017-12-12T00:00:00.000Z",
total: 2,
sumOfTotal: 3 //summed up with the previous
}
{
createdAt: "2018-01-01T00:00:00.000Z",
total: 2,
sumOfTotal: 5 //summed up with the previous
}
],
categotyList: [ //list ordered by category
{
category: "category1",
total: 2
},
{
category: "category2",
total: 2
},
{
category: "category3",
total: 1
}
]
},
...
Is possible to do this in the same aggregate?
I do not think it really makes sense to have the createdAtList.sumOfTotal field. I do not think the fields in an array should be dependent upon a particular order of the elements. If you want some field to contain the sum of the createdAtList.total field, I think there should only be one field (outside of the array). That being said, here is the query I came up with to give you the desired results (using "users" as the name of the collection):
db.users.aggregate([
{
$group: {
_id: {
user: "$user",
createdAt: "$createdAt"
},
total: { $sum: 1 },
category: { $push: "$category" }
}
},
{
$project: {
_id: 0,
user: "$_id.user",
createdAt: "$_id.createdAt",
total: "$total",
category: 1
}
},
{ $unwind: "$category" },
{
$group: {
_id: {
user: "$user",
category: "$category"
},
catTotal: { $sum: 1 },
createdAtList: {
$push: {
createdAt: "$createdAt",
total: "$total"
}
}
}
},
{
$project: {
_id: 0,
user: "$_id.user",
createdAtList: 1,
category: "$_id.category",
catTotal: 1
}
},
{ $unwind: "$createdAtList" },
{
$group: {
_id: "$user",
createdAtList: {
$addToSet: "$createdAtList"
},
categoryList: {
$addToSet: {
category: "$category",
total: "$catTotal"
}
}
}
},
{ $unwind: "$createdAtList" },
{ $sort: { "createdAtList.createdAt": 1 } },
{
$group: {
_id: "$_id",
createdAtList: {
$push: "$createdAtList"
},
categoryList: {
$first: "$categoryList"
}
}
},
{ $unwind: "$categoryList" },
{ $sort: { "categoryList.category": 1 } },
{
$group: {
_id: "$_id",
createdAtList: {
$first: "$createdAtList"
},
categoryList: {
$push: "$categoryList"
}
}
},
{
$project: {
_id: 0,
user: "$_id",
createdAtList: 1,
sumOfTotal: { $sum: "$createdAtList.total" },
categoryList: 1
}
},
{ $sort: { user: 1 } },
]).pretty()