$group and $lookup is not giving proper data - mongodb

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.

Related

MongoDB aggregate data using $agg

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

How to get a field of an object in document?

I am not sure how to phrase this question properly but basically I have an "Order" Schema and each order model contains an array of product objects created using "Product" Schema
When I create an order, my req.body is this
body: {
orderItems: [ [Object] ],
shippingAddress: {
fullName: '123',
address: '1231',
city: '123',
postalCode: '123',
country: '123'
},
shippingPrice: 0,
paymentMethod: 'Stripe',
itemsPrice: 338,
totalPrice: 338
},
If I log req.body.orderItems, I can see each product object printed
{
_id: new ObjectId("62d51a3895cad3ca283302f3"),
name: 'Christmas Cake',
slug: 'christmas-cake',
image: '/images/cake.jpg',
shop: 'Custom Cakes',
category: 'food',
description: 'Custom baked christmas cake, pre-order needed.',
price: 70,
stock: 1,
rating: 3,
numReviews: 2,
__v: 2,
createdAt: 2022-07-18T08:30:48.931Z,
updatedAt: 2022-07-20T03:03:00.592Z,
}
{
_id: new ObjectId("62d7a8c126dcacfc13055e3d"),
name: 'cake',
slug: 'cake',
image: '/images/cake.jpg',
shop: 'Custom Cakes',
category: 'food',
description: 'cake',
price: 15,
stock: 2,
rating: 0,
numReviews: 0,
user: { _id: new ObjectId("62d51d57c08cd7e6675e8d45")},
reviews: [],
createdAt: 2022-07-20T07:03:29.372Z,
updatedAt: 2022-07-20T07:03:59.315Z,
__v: 0
}
But I am unable to obtain the 'shop' field. req.body.orderItems.shop returns undefined

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.

MongoDb Aggregate per subdocument

I have these collections, stats and items. Stats has one item as subdocument:
var ItemSchema = new Schema({
type: String,
created_at: Date,
updated_at: {
type: Date,
default: Date.now()
}
});
var StatsSchema = new Schema({
item: {
type: Schema.ObjectId,
ref: 'Item'
},
url: String,
date: Date,
action: String,
hourly: Number
});
I'd like to aggregate Stats grouping by item.type. Is it possible?
I tried something like this but without luck:
db.stats.aggregate(
{ $project: { _id: 1, hourly: 1, action: 1, item: 1, type: '$item.type' } },
{ $group: { _id: { action: '$action', type: '$item.type' }, total: { $sum: '$hourly' } } }
)
You should not need the $project part of the pipeline.
You should be get what you need from the $group stage
db.stats.aggregate({ $group: { _id: "$item.type" , total: { $sum: '$hourly' } } });