How to get a field of an object in document? - mongodb

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

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.

Mongoose: Get the data from 2 collections, like get products that have same category type like fruits

I am very new to mongoDB and mongoose and I also know questions like this has been already asked but still I didn't get any luck.
So what I am trying to do is I have 2 collections one is products and second is categories and I am trying to get the products that are of category type: fruits
product.model.js
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category'
},
name: {
type: String,
required: true,
unique: true
},
price: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
description: {
type: String,
required: true
}
})
const Product = mongoose.model('Product', productSchema)
module.exports = Product
category.model.js
const mongoose = require('mongoose')
const categorySchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
lowercase: true
}
})
const Category = mongoose.model('Category', categorySchema)
module.exports = Category
products collecction
[ { _id: 5ffc9795355f3707ec326f51,
name: 'apple',
price: 80,
image: 'apple1.jpg',
description:
'Do you really need description for this ??',
category: 5ffc94e8a7542a37101a119c,
__v: 0 },
{ _id: 5ffd54409793c33b183376b8,
name: 'Beef',
price: 180,
image: 'beef1.jpg',
description: 'Don\'t you dare to ask about beef in india',
category: 5ffc94dda7542a37101a119b,
__v: 0 },
{ _id: 5ffd54969793c33b183376b9,
name: 'Mango',
price: 100,
image: 'mango1.jpg',
description:
'Have some manog because you cannot eat the bottle of slice like katrina kaif do, its crazy',
category: 5ffc94e8a7542a37101a119c,
__v: 0 } ]
categories collection
[ { _id: 5ffc947ea7542a37101a119a, name: 'vegitables', __v: 0 },
{ _id: 5ffc94dda7542a37101a119b, name: 'non-veg', __v: 0 },
{ _id: 5ffc94e8a7542a37101a119c, name: 'fruits', __v: 0 } ]
Now I want to the get the products whose category are fruits
I know I have to use aggregation and lookup for this I also tried but didn't get any luck, this is my code
const Product = require('./models/product')
const Category = require('./models/category')
const test = async () => {
try {
var query = [
{
$lookup: {
from: "product",
localField: "category",
foreignField: "_id",
as: "product"
}
}]
const productCate = await Product.aggregate(query)
console.log(productCate)
// const productCat = await Product.find().populate({
// path: 'category',
// match: {name: 'fruits'}
// }).exec()
// console.log(productCat)
}catch(e) {
}
}
test()
UPDATE-1
I also tried ppuplate but still didn't get the response as expected, this is my code:
const test = async () => {
try {
const productCat = await Product.find().populate({
path: 'category',
match: {name: 'fruits'}
}).exec()
console.log(productCat)
}catch(e) {
}
}
test()
this is my output
[ { _id: 5ffc9795355f3707ec326f51,
name: 'apple',
price: 80,
image: 'apple1.jpg',
description:
'Do you really need description for this, how dumb are you ??',
category: { _id: 5ffc94e8a7542a37101a119c, name: 'fruits', __v: 0 },
__v: 0 },
{ _id: 5ffd54409793c33b183376b8,
name: 'Beef',
price: 180,
image: 'beef1.jpg',
description: 'Don\'t you dare to ask about beef in india',
category: null,
__v: 0 },
{ _id: 5ffd54969793c33b183376b9,
name: 'Mango',
price: 100,
image: 'mango1.jpg',
description:
'Have some manog because you cannot eat the bottle of slice like katrina kaif do, its crazy',
category: { _id: 5ffc94e8a7542a37101a119c, name: 'fruits', __v: 0 },
__v: 0 } ]
Here I also get the beef that is fall under non-veg category but with the category null. Actually I only want the fruits category products.
you can following this code
const test = async () => {
try {
let categoryId = await Category.findOne({name:"fruits"}).select("_id")
const productCat = await Product.find({category:categoryId}).populate(
"category"
).lean()
console.log(productCat)
}catch(e) {
}
}
test()
you can do with with populate match without using aggregation:
Product.find().populate({
path: 'category',
match: { 'name': 'fruits' }
})
.exec()

Populate data in mongoose on collections(generated by strapi.io)

I have 3 collections in mongodb generated by strapi.io, I want customize query populate data by mongoose in my project. But i cannot populate data like strapi result.
Category collection:
{
_id: "5d10a731c5077836540bebf0",
posts: [
"5d10a6fbc5077836540bebed",
"5d10af45c5077836540bebf1"
],
name: "Support",
ids: "support",
keywords: "support",
des: "support des",
createdAt: "2019-06-24T10:34:25.383Z",
updatedAt: "2019-06-24T11:08:53.475Z",
__v: 0,
id: "5d10a731c5077836540bebf0"
}
Post collection:
{
_id: "5d10af45c5077836540bebf1",
ids: "test",
title: "this is test",
des: "test",
keywords: "test",
body: "testtesttesttesttest",
createdAt: "2019-06-24T11:08:53.467Z",
updatedAt: "2019-06-24T11:08:53.477Z",
__v: 0,
id: "5d10af45c5077836540bebf1"
}
FileUpload collection:
{
_id: "5d10af45c5077836540bebf2",
name: "THUMBNAIL.png",
sha256: "0bP9PI3R_ygF07cLhg5U-syLeVCz4ZbBrwZZi2OtPL4",
hash: "9f4e8bbd13b94f2baa3d26b335124717",
ext: ".png",
mime: "image/png",
size: "297.33",
url: "/uploads/9f4e8bbd13b94f2baa3d26b335124717.png",
provider: "local",
related:
[
{
_id: "5d10af45c5077836540bebf3",
ref: "5d10af45c5077836540bebf1",
kind: "Post",
field: "pic"
}
],
createdAt: "2019-06-24T11:08:53.501Z",
updatedAt: "2019-06-24T11:08:53.505Z",
__v: 0,
id: "5d10af45c5077836540bebf2"
}
I can populate "posts" on Category model with
Cat.find().populate({path: 'posts',model: 'Post'})
But I can not populate "categories" and "pic" on Post model.
How can I populate "categories" and "pic" like this result of strapi:
{
_id: "5d10af45c5077836540bebf1",
ids: "test",
title: "this is test",
des: "test",
keywords: "test",
body: "testtesttesttesttest",
createdAt: "2019-06-24T11:08:53.467Z",
updatedAt: "2019-06-24T11:08:53.477Z",
__v: 0,
id: "5d10af45c5077836540bebf1",
pic: {
_id: "5d10af45c5077836540bebf2",
name: "THUMBNAIL.png",
sha256: "0bP9PI3R_ygF07cLhg5U-syLeVCz4ZbBrwZZi2OtPL4",
hash: "9f4e8bbd13b94f2baa3d26b335124717",
ext: ".png",
mime: "image/png",
size: "297.33",
url: "/uploads/9f4e8bbd13b94f2baa3d26b335124717.png",
provider: "local",
related: [
"5d10af45c5077836540bebf1"
],
createdAt: "2019-06-24T11:08:53.501Z",
updatedAt: "2019-06-24T11:08:53.505Z",
__v: 0,
id: "5d10af45c5077836540bebf2"
},
categories:
[
{
posts: [
"5d10a6fbc5077836540bebed",
"5d10af45c5077836540bebf1"
],
_id: "5d10a731c5077836540bebf0",
name: "Support",
ids: "support",
keywords: "support",
des: "support des",
createdAt: "2019-06-24T10:34:25.383Z",
updatedAt: "2019-06-24T11:08:53.475Z",
__v: 0,
id: "5d10a731c5077836540bebf0"
}
]
}
you have to create another collection inside the post. as like you have an independent collection then you can populate. for example :
Post: {body: ,title: ,Image : { image: {name : , etc }}}
this can be a collection inside collection. the above code is not correct you have to mention your own fields.