MongoDB aggregate data using $agg - mongodb

So i try to aggregate the data from mongoDB using $match and $group to get the exact value an d format with data from mongoDB in JSON as Below:
[ {
_id: new ObjectId("6357b4237cf79bba3e66c096"),
userId: new ObjectId("635762fe85b94eac7466d965"),
formId: new ObjectId("6357921d49de88bb7fffcfe4"),
title: 'Quality',
username: 'Jansenstan24#gmail.coms',
date: '2022-10-25',
answer: {
'6357921d49de88bb7fffcfe8': 'john#nabatisnack.com',
Text: 'john#nabatisnack.com',
'6357b331235053a9d4e8d037': 'john#dose.com',
Email: 'john#dose.com',
'6357b335235053a9d4e8d03a': 'Maja',
Plant: 'Maja'
},
createdAt: 1666692131,
updatedAt: 1666692131,
__v: 0
},
{
_id: new ObjectId("6357b54922866fae378af370"),
userId: new ObjectId("635762fe85b94eac7466d965"),
formId: new ObjectId("6357921d49de88bb7fffcfe4"),
title: 'Quality',
username: 'Jansenstan24#gmail.coms',
date: '2022-10-25',
answer: {
'6357921d49de88bb7fffcfe8': 'john#dose.com',
Text: 'john#dose.com',
'6357b331235053a9d4e8d037': 'john#nabatisnack.com',
Email: 'john#nabatisnack.com',
'6357b335235053a9d4e8d03a': 'Cica',
Plant: 'Cica'
},
createdAt: 1666692425,
updatedAt: 1666692425,
__v: 0
},
{
_id: new ObjectId("6357b6a2a13ab3c4a462be8f"),
userId: new ObjectId("635647c1e24d0a4482e3c0a9"),
formId: new ObjectId("6357921d49de88bb7fffcfe4"),
title: 'Quality',
username: 'adam#wegodev.com',
date: '2022-10-25',
answer: {
'6357921d49de88bb7fffcfe8': '12',
Text: '12',
'6357b331235053a9d4e8d037': 'john#dose.coms',
Email: 'john#dose.coms',
'6357b335235053a9d4e8d03a': 'Ranca',
Plant: 'Ranca'
},
createdAt: 1666692770,
updatedAt: 1666692770,
__v: 0
}]
using this line of code in javascript:
forms = await Answer.aggregate([
{
$match: { title: "Quality" },
},
{ $group: { title: "Quality"} },
]);
what i expected is the result like this:
{
formId: new ObjectId("6357921d49de88bb7fffcfe4"),
title: 'Quality',
username: [{'Jansenstan24#gmail.coms',adam#wegodev.com}]
date: [{'2022-10-25','2022-10-26}]
answer: [{
'6357921d49de88bb7fffcfe8': 'john#nabatisnack.com',
Text: 'john#nabatisnack.com',
'6357b331235053a9d4e8d037': 'john#dose.com',
Email: 'john#dose.com',
'6357b335235053a9d4e8d03a': 'Maja',
Plant: 'Maja'
},{
'6357921d49de88bb7fffcfe8': 'john#dose.com',
Text: 'john#dose.com',
'6357b331235053a9d4e8d037': 'john#nabatisnack.com',
Email: 'john#nabatisnack.com',
'6357b335235053a9d4e8d03a': 'Cica',
Plant: 'Cica'
},...etc],
},
i try to use more complex query but it seems it not return the result i want and i've try to seek any related problem but it wont return the same result as i want

You have the right idea using $group, you just need to leverage it's syntax properly, like so:
db.collection.aggregate([
{
$match: {
title: "Quality"
}
},
{
$group: {
_id: "$title",
title: {
$first: "$title"
},
username: {
"$addToSet": "$username"
},
date: {
$addToSet: "$date"
},
formId: {
$addToSet: "$formId"
},
answer: {
$push: "$answer"
}
}
}
])
Mongo Playground

Related

$group and $lookup is not giving proper data

I am having code like this
const aggregate = [];
const lookup = {
$lookup: {
from: "balances",
localField: "accountNumber",
foreignField: "account_id",
as: "bankbalance",
},
};
const unwind = {
$unwind: "$bankbalance",
};
const match = {
$match: {
"bankbalance.date": {
$gte: startDate,
$lte: endDate,
},
userId: mongoose.Types.ObjectId(userId),
isActive: 1,
type: "accountType"
},
};
const group = {
$group: {
_id: '$_id',
accountNumber:{"$first":"$accountNumber"},
balances: {
$addToSet: { date: "$$ROOT.date", amount: "$$ROOT.amount" },
},
},
};
aggregate.push(lookup);
aggregate.push(unwind);
aggregate.push(group);
aggregate.push(match);
let data = await BankAccounts.aggregate(aggregate);
this code is giving me empty [] data, if I do not use $group then its giving data like this
{
_id: 611bc2c4f9649b2c6fe4007f,
bankId: 'string',
mask: '0000',
name: 'Plaid Checking',
userId: 611bc2794d9f391bf2cd7877,
accountNumber: 'xxxxxxxxxxxxxxxxxxx',
bankTokenId: xxxxxxxxxxxxxxxxxxxxxxxxxxx,
createdAt: 2021-08-17T14:08:04.058Z,
isConnected: true,
subtype: 'checking',
type: 'depository',
updatedAt: 2021-08-25T11:36:37.824Z,
isActive: 1,
bankbalance: {
_id: 61262b9bf9649b2c6fe7d67c,
ISODate: '2021-05-19T00:00:00.000Z',
account_id: 'xxxxxxxxxxxxxxxxxxxxxxxx',
userId: 611bc2794d9f391bf2cd7877,
ISOCountryCode: null,
accountId: xxxxxxxxxxxxxxxxxxxx,
amount: -1047.62,
bankTokenId: xxxxxxxxxxxxxxxxxxxx,
createdAt: 2021-08-25T11:37:26.960Z,
current: null,
date: '2021-05-19',
institutionId: xxxxxxxxxxxxxxxxxxxxxx,
isActive: 1,
unofficialCountryCode: null,
updatedAt: 2021-08-25T11:37:26.960Z
}
},
{
_id: 611bc2c4f9649b2c6fe4007f,
bankId: 'string',
mask: '0000',
name: 'Plaid Checking',
userId: 611bc2794d9f391bf2cd7877,
accountNumber: 'xxxxxxxxxxxxxxxxxxx',
bankTokenId: xxxxxxxxxxxxxxxxxxxxxxxxxxx,
createdAt: 2021-08-17T14:08:04.058Z,
isConnected: true,
subtype: 'checking',
type: 'depository',
updatedAt: 2021-08-25T11:36:37.824Z,
isActive: 1,
bankbalance: {
_id: 61262b99f9649b2c6fe7d671,
ISODate: '2021-05-24T00:00:00.000Z',
account_id: 'xxxxxxxxxxxxxxxxxxxxxxxx',
userId: 611bc2794d9f391bf2cd7877,
ISOCountryCode: null,
accountId: xxxxxxxxxxxxxxxxxxxx,
amount: -1137.02,
bankTokenId: xxxxxxxxxxxxxxxxxxxx,
createdAt: 2021-08-25T11:37:26.960Z,
current: null,
date: '2021-05-24',
institutionId: xxxxxxxxxxxxxxxxxxxxxx,
isActive: 1,
unofficialCountryCode: null,
updatedAt: 2021-08-25T11:37:26.960Z
}
}
this is giving all data record again and again, here reference between 2 collection is accountNumber and account_id. I want to group all records in 1 like
{
_id: 611bc2c4f9649b2c6fe4007f,
bankId: 'string',
mask: '0000',
name: 'Plaid Checking',
userId: 611bc2794d9f391bf2cd7877,
accountNumber: 'xxxxxxxxxxxxxxxxxxx',
bankTokenId: xxxxxxxxxxxxxxxxxxxxxxxxxxx,
createdAt: 2021-08-17T14:08:04.058Z,
isConnected: true,
subtype: 'checking',
type: 'depository',
updatedAt: 2021-08-25T11:36:37.824Z,
isActive: 1,
bankbalance: [{
_id: 61262b99f9649b2c6fe7d671,
ISODate: '2021-05-24T00:00:00.000Z',
account_id: 'xxxxxxxxxxxxxxxxxxxxxxxx',
userId: 611bc2794d9f391bf2cd7877,
ISOCountryCode: null,
accountId: xxxxxxxxxxxxxxxxxxxx,
amount: -1137.02,
bankTokenId: xxxxxxxxxxxxxxxxxxxx,
createdAt: 2021-08-25T11:37:26.960Z,
current: null,
date: '2021-05-24',
institutionId: xxxxxxxxxxxxxxxxxxxxxx,
isActive: 1,
unofficialCountryCode: null,
updatedAt: 2021-08-25T11:37:26.960Z
},
{
_id: 61262b9bf9649b2c6fe7d67c,
ISODate: '2021-05-19T00:00:00.000Z',
account_id: 'xxxxxxxxxxxxxxxxxxxxxxxx',
userId: 611bc2794d9f391bf2cd7877,
ISOCountryCode: null,
accountId: xxxxxxxxxxxxxxxxxxxx,
amount: -1047.62,
bankTokenId: xxxxxxxxxxxxxxxxxxxx,
createdAt: 2021-08-25T11:37:26.960Z,
current: null,
date: '2021-05-19',
institutionId: xxxxxxxxxxxxxxxxxxxxxx,
isActive: 1,
unofficialCountryCode: null,
updatedAt: 2021-08-25T11:37:26.960Z
}
]
}
also sort bankbalance by date. Any help! Thanks in advance!!
The stages are in the order
aggregate.push(lookup);
aggregate.push(unwind);
aggregate.push(group);
aggregate.push(match);
When the group stage executes, each document will have only the fields noted in that stage. i.e.
{
_id: 611bc2c4f9649b2c6fe4007f,
accountNumber: 'xxxxxxxxxxxxxxxxxxx',
balances: [ {date: ......, amount: .....} ]
}
When the match stage executes, the fields "bankbalance.date", userId, isActive, and type don't exist, so no documents satisfy the match.

Strapi mongodb project specific fields in embedded documents

I'm trying to select especific fields from this document
{
_id: 60d9295db34f1c0144c9b8d4,
title: 'Este es el titulo',
slug: 'este-es-el-titulo',
date: '2021-06-27',
category: {
_id: 60d92921b34f1c0144c9b8d2,
title: 'Categoria 1',
slug: 'categoria-1',
id: '60d92921b34f1c0144c9b8d2'
},
cover: {
_id: 60d72c815e57e6015e38a4c7,
name: 'project4.png',
alternativeText: '',
caption: '',
hash: 'project4_3e8c906bdf',
ext: '.png',
mime: 'image/png',
size: 540.02,
width: 1895,
height: 883,
url: '/uploads/project4_3e8c906bdf.png',
formats: [Object],
provider: 'local',
related: [Array],
createdAt: 2021-06-26T13:32:49.389Z,
updatedAt: 2021-06-28T01:43:57.469Z,
__v: 0,
created_by: '60d69246c6f06d00f64312b0',
updated_by: '60d69246c6f06d00f64312b0',
id: '60d72c815e57e6015e38a4c7'
},
id: '60d9295db34f1c0144c9b8d4'
}
and I want get something like this:
{
_id: 60d9295db34f1c0144c9b8d4,
title: 'Este es el titulo',
slug: 'este-es-el-titulo',
date: '2021-06-27',
category: {
_id: 60d92921b34f1c0144c9b8d2,
title: 'Categoria 1',
slug: 'categoria-1',
id: '60d92921b34f1c0144c9b8d2'
},
cover: { url: '/uploads/project4_3e8c906bdf.png'}
id: '60d9295db34f1c0144c9b8d4'
}
I'm using Strapi with Mongodb and y was trying with the following code:
const requiredData = {
title: 1,
slug: 1,
date: 1,
category: 1,
cover: { url: 1 }
}
const populateData = [
{
path: 'category',
select: ['title', 'slug']
}
]
let editorsPick = await strapi.query('posts')
.model.find({ editorsPick: true}, requiredData)
.limit(3)
.populate(populateData)
But I only have this:
{
_id: 60d9295db34f1c0144c9b8d4,
title: 'Este es el titulo',
slug: 'este-es-el-titulo',
date: '2021-06-27',
category: {
_id: 60d92921b34f1c0144c9b8d2,
title: 'Categoria 1',
slug: 'categoria-1',
id: '60d92921b34f1c0144c9b8d2'
},
id: '60d9295db34f1c0144c9b8d4'
}
(Without cover image), and then try with:
let editorsPick = await strapi.query('posts')
.model.aggregate([
{"$match": { editorsPick: true}},
{"$project": requiredData}
])
But I got an empty array []
Please I need a little help, and sorry for my english

How to get this parent child query data in Mongo DB

I am building a simple messaging system and I have a messageSchema which is setup as below:
const messageSchema = new mongoose.Schema({
replyTo: {
type: mongoose.Schema.ObjectId,
ref: 'Message',
default: null,
},
name: {
type: Object,
required: [true, 'Message has a name'],
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
},
email: {
type: Object,
required: [true, 'Message has a email'],
},
subject: {
type: String,
required: [true, 'Message has a subject'],
},
content: {
type: String,
required: [true, 'Message has content'],
},
createdAt: {
type: Date,
default: Date.now(),
},
status: {
type: String,
default: 'unread',
required: [true, 'Message has a status'],
},});
Sample data below:
[
{
_id: ObjectId('53ed7efca75ca1a5248a281a'),
name: 'Person 1',
createdAt: ISODate('2021-01-01T01:00:00.000Z'),
subject: 'M1',
content: 'M1 content',
replyTo: null,
},
{
_id: ObjectId('53ed80bba75ca1a5248a281b'),
name: 'Person 2',
subject: 'M2 - Reply 1 to M1',
content: 'M2 content',
createdAt: ISODate('2021-01-01T02:00:00.000Z'),
replyTo: ObjectId('53ed7efca75ca1a5248a281a'),
},
{
_id: ObjectId('53ed80bba75ca1a5248a281c'),
name: 'Person 3',
subject: 'M3 - Reply 2 to M1',
content: 'M3 content',
createdAt: ISODate('2021-01-01T03:00:00.000Z'),
replyTo: ObjectId('53ed7efca75ca1a5248a281a'),
},
{
_id: ObjectId('53ed80bba75ca1a5248a281d'),
name: 'Person 4',
subject: 'M4',
content: 'M4 content',
createdAt: ISODate('2021-01-01T02:30:00.000Z'),
replyTo: null,
},
];
I am now trying to query the sample above to produce an inbox style response, so that the root message (no replyTo) is the top-level message, has a latest node with latest message info, and has children(if any) in a children node. See below for desired output.
[
{
_id: ObjectId('53ed7efca75ca1a5248a281a'),
name: 'Person 1',
createdAt: ISODate('2021-01-01T01:00:00.000Z'),
subject: 'M1',
content: 'M1 content',
replyTo: null,
latest: {
_id: ObjectId('53ed80bba75ca1a5248a281c'),
name: 'Person 3',
subject: 'M3 - Reply 2 to M1',
content: 'M3 content',
createdAt: ISODate('2021-01-01T03:00:00.000Z'),
replyTo: ObjectId('53ed7efca75ca1a5248a281a'),
},
children: [
{
_id: ObjectId('53ed80bba75ca1a5248a281b'),
name: 'Person 2',
subject: 'M2 - Reply 1 to M1',
content: 'M2 content',
createdAt: ISODate('2021-01-01T02:00:00.000Z'),
replyTo: ObjectId('53ed7efca75ca1a5248a281a'),
},
{
_id: ObjectId('53ed80bba75ca1a5248a281c'),
name: 'Person 3',
subject: 'M3 - Reply 2 to M1',
content: 'M3 content',
createdAt: ISODate('2021-01-01T03:00:00.000Z'),
replyTo: ObjectId('53ed7efca75ca1a5248a281a'),
},
]
},
{
_id: ObjectId('53ed80bba75ca1a5248a281d'),
name: 'Person 4',
subject: 'M4',
content: 'M4 content',
createdAt: ISODate('2021-01-01T02:30:00.000Z'),
replyTo: null,
latest: {
_id: ObjectId('53ed80bba75ca1a5248a281d'),
name: 'Person 4',
subject: 'M4',
content: 'M4 content',
createdAt: ISODate('2021-01-01T02:30:00.000Z'),
replyTo: null,
},
children: []
},];
Appreciate any help in getting this query sorted. Thanks.
You can use aggregation pipeline stages,
$match replyTo us null condition
$graphLookup to join same collection to get reply messages in children
$addFields to check condition is children is empty then return root document otherwise return last element from children
db.collection.aggregate([
{ $match: { replyTo: null } },
{
"$graphLookup": {
"from": "collection",
"startWith": "$_id",
"connectFromField": "_id",
"connectToField": "replyTo",
"as": "children"
}
},
{
$addFields: {
latest: {
$cond: [
{ $eq: [{ $size: "$children" }, 0] },
"$$ROOT",
{ $arrayElemAt: [{$slice: ["$children", -1]}, 0] }
]
}
}
}
])
Playground
For query optimization you can do last stage $addFields process in your client side.

How to append data to existing array in mongodb in MERN stack

I have an existing array which looks like this
{
_id: 5f14675a4fb8565fb89ec338,
name: 'sample5',
email: 'sample5#test.com',
rollno: 9,
city: [
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 1',
citycode: '000000'
}
],
__v: 0
}
So I want to append the data to the existing array which is
city: [
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 2',
citycode: '000002'
}
],
So my final db should look like this
{
_id: 5f14675a4fb8565fb89ec338,
name: 'sample5',
email: 'sample5#test.com',
rollno: 9,
city: [
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 1',
citycode: '000000'
},
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 2',
citycode: '000002'
},
],
__v: 0
}
For now I am just able to update my existing data where I show the cityname and citycode and if the user make any changes it is reflected in the database.
Code I am using to update the database
// Update Student
router.route('/update-student/:id').put((req, res, next) => {
studentSchema.findByIdAndUpdate(req.params.id, {
$set: req.body
}, (error, data) => {
if (error) {
return next(error);
console.log(error)
} else {
// $push:{
res.json(data)
console.log('Student updated successfully !')
// }
}
})
})
Schema structure
let studentSchema = new Schema({
name: {
type: String
},
email: {
type: String
},
rollno: {
type: Number
},
city: [{
cityname: {type: String},
citycode: {type: String},
}],
},
{
collection: 'students'
})
And then in routes it is updated using $push method
// Update Student
router.route('/update-student/:id').put((req, res, next) => {
studentSchema.findByIdAndUpdate(req.params.id, {
$push: req.body
}, (error, data) => {
if (error) {
return next(error);
console.log(error)
} else {
// $push:{
res.json(data)
console.log('Student updated successfully !')
// }
}
})
})
OUTPUT
[{_id: "5f12e5158be2503422bf6982", name: "sample1", email: "sample1#test.com", rollno: 1,…},…]
0: {_id: "5f12e5158be2503422bf6982", name: "sample1", email: "sample1#test.com", rollno: 1,…}
city: [{_id: "5f146fb84fb8565fb89ec33c", cityname: "city3", citycode: "12345"},…]
0: {_id: "5f146fb84fb8565fb89ec33c", cityname: "city3", citycode: "12345"}
citycode: "12345"
cityname: "city3"
_id: "5f146fb84fb8565fb89ec33c"
1: {_id: "5f15301f67c1992f4a233f77", cityname: "new city", citycode: "new code"}
citycode: "new code"
cityname: "new city"
_id: "5f15301f67c1992f4a233f77"
email: "sample1#test.com"
name: "sample1"
rollno: 1
__v: 0
_id: "5f12e5158be2503422bf6982"
Check out This answer you might need to use the $push in your query to achieve what you want.
SOLUTION
When the submit button is clicked. The array is stored in city as the schema is in this manner. This schema structure is there above. It is then passed to the db using axios.
onSubmit(e) {
e.preventDefault()
const studentObject = {
city: [{cityname: this.state.cityname, citycode: this.state.citycode}]
};
axios.put('http://localhost:4000/students/update-student/' + this.props.match.params.id, studentObject)
.then((res) => {
console.log(res.data)
console.log('Student successfully updated')
}).catch((error) => {
console.log(error)
})
// Redirect to Student List
this.props.history.push('/student-list')
}

how to find exact array with given conditions

assume i have an document
{ _id: 5e53c14c561efe357053a818,
convoId: 5e53c14c561efe357053a816,
message:
[ { isRead: true,
createdAt: 2020-02-24T12:27:56.085Z,
_id: 5e53c14c561efe357053a819,
senderId: 5e4e50a5ae51b02f08f174eb,
recieverId: 5e4ae76bd4e24418a020b665,
body: 'hiii' },
{ isRead: true,
createdAt: 2020-02-24T12:29:12.333Z,
_id: 5e53c198561efe357053a81c,
senderId: 5e4e50a5ae51b02f08f174eb,
recieverId: 5e4ae76bd4e24418a020b665,
body: 'jawab de' },
{ isRead: true,
createdAt: 2020-02-24T15:17:12.954Z,
_id: 5e53e8f8d22dd714ac7f1ee1,
senderId: 5e4e50a5ae51b02f08f174eb,
recieverId: 5e4ae76bd4e24418a020b665,
body: 'hi again' },
{ isRead: true,
createdAt: 2020-02-25T21:07:15.695Z,
_id: 5e558c8367d9d61e2c52d0db,
senderId: 5e4ae76bd4e24418a020b665,
recieverId: 5e4e50a5ae51b02f08f174eb,
body: 'whats up??' },
{ isRead: true,
createdAt: 2020-02-25T21:11:20.653Z,
_id: 5e558d7867d9d61e2c52d0dc,
senderId: 5e4ae76bd4e24418a020b665,
recieverId: 5e4e50a5ae51b02f08f174eb,
body: 'yoyoy' },
{ isRead: false,
createdAt: 2020-02-25T21:12:30.743Z,
_id: 5e558dbe67d9d61e2c52d0dd,
senderId: 5e4e50a5ae51b02f08f174eb,
recieverId: 5e4ae76bd4e24418a020b665,
body: 'nothing much' } ],
__v: 0 }
i want an array in which senderId is equal to 5e4e50a5ae51b02f08f174eb
here what i have done so far
const message = await Message.findOne({
"message.senderId": "5e4e50a5ae51b02f08f174eb",
});
but am getting whole result basically i want to filter message array with only 5e4e50a5ae51b02f08f174eb this senderId
i can also done with this
const updatedMessage = message.message.filter(msg => {
return msg.senderId == "5e4e50a5ae51b02f08f174eb"
})
but i want to know is there any other method??