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

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()

Related

mongodb match in aggregate is not working

I have the following 2 schemas:
bookSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'Name required']
},
author:{
type:mongoose.Schema.ObjectId,
ref: 'Author'
}
authorSchema = new mongoose.Schema(
{
name: {
type: String,
trim: true,
})
I have an array of Author object references and I need to filter books based on these:
authors: [
{
_id: new ObjectId("6358edf901dbe13bc738b63b"),
name: 'Name 2',
__v: 0
},
{
_id: new ObjectId("63592660ca309b7c1a94fb04"),
name: 'Name 1',
__v: 0
}
]
I have tried with below code but it gives empty array as result:
Book.aggregate([ { $match: { $expr: { $in: ['Author', authors] } } } ,])

Aggregate data and populate in one request

I am a bit puzzled by populate in MongoDB.
I've got a Schema:
import { Schema, Document, model } from "mongoose";
export interface ProductGroupType {
id: Schema.Types.ObjectId,
title: String,
name: String,
description: String,
}
const ProductGroupSchema: Schema<Document<ProductGroupType>> = new Schema({
title: { type: String, trim: true },
name: { type: String, trim: true },
description: { type: String, trim: true },
}, { collection: "productGroups", timestamps: true });
export const ProductGroupModel = model('ProductGroup', ProductGroupSchema);
and products
import { Schema, Document, model } from "mongoose";
import { plugin as autocomplete } from 'mongoose-auto-increment';
const ProductSchema: Schema<Document<IProduct>> = new Schema({
article: Number,
name: String,
category: { type: Schema.Types.ObjectId, ref: 'ProductCategory' },
group: { type: Schema.Types.ObjectId, ref: 'ProductGroup' },
price: { type: Number, default: 0 },
discount: { type: Number, default: 0 },
stock: {
available: { type: Number, default: 0 },
reserved: { type: Number, default: 0 },
},
images: [Object],
description: String,
productDetails: Object,
}, { collection: "products", timestamps: true });
ProductSchema.plugin(autocomplete, {
model: 'Product',
field: 'article',
startAt: 10000,
});
export const ProductModel = model('Product', ProductSchema);
I need to make a request and group on the MongoDB side data by the field 'group'.
I can make this like this:
await ProductModel.aggregate([
{ $match: { category: Types.ObjectId(queryCategory.id) } },
{
$group: {
_id: '$group',
products: {
$push: {
id: '$_id',
name: '$name',
article: '$article',
price: '$price',
discount: '$discount',
description: '$description',
group: '$groupName',
}
},
count: { $sum: 1 },
}
},
]);
but the output here is:
[
{ _id: 61969583ad32e113f87d0e99, products: [ [Object] ], count: 1 },
{
_id: 61993fff452631090bfff750,
products: [ [Object], [Object] ],
count: 2
}
]
almost what I need but I've been playing around with population and I cannot make it work with Aggregation framework.
I already tried to use the 'lookup' operator but it returns an empty array and doesn't want to work.
That's how I wanted to make it work:
const products: Array<IProduct> = await ProductModel.aggregate([
{ $match: { category: Types.ObjectId(queryCategory.id) } },
{
$group: {
_id: '$group',
products: {
$push: {
id: '$_id',
name: '$name',
article: '$article',
price: '$price',
discount: '$discount',
description: '$description',
group: '$groupName',
}
},
count: { $sum: 1 },
}
},
{
$lookup: {
"from": "productGroups",
"localField": "group",
"foreignField": "_id",
"as": "groupName"
},
},
]);
Is it possible to get the same result as I've got now but populate in the same query group field?
So far the only way I've managed to populate it like this as the second request:
await ProductGroupModel.populate( products.map( (product: any) => {
return {
_id: new ProductGroupModel(product),
products: product.products,
count: product.count,
}
} ), { "path": "_id" } )
In a MongoDB aggregation pipeline, the $group stage passes along only those field explicitly declared in the stage.
In the same pipeline you show, the documents passed along by the $group stage would contain the fields:
_id
products
count
When the exector arrives a the $lookup stage, none of the documents contain a field named group.
However, the value previously contained in the group field still exists, in the _id field.
In the $lookup stage, use
"localField": "_id",
to find documents based on that value.

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

mongodb pull function why not working in my situation?

i make simple board app. but i face scrab problem.
i want to pull data in scrabContent when people unscrab. but it doesnt' work. help me plz..
My Schema looks like this. scrabContent means contents that i scrab. So, when i scrab some contents, they are stored in scrabContent.
const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required:true,
unique: true,
},
follower : [String],
following : [String],
boardBookmark: [],
scrabContent: [],
songs: [],
songsView: {
type: Number,
default :0,
},
profileImage: {
type: String,
}
});
this is schema data example.
{
follower: [],
following: [],
boardBookmark: [
{
name: 'asd',
introduction: 'dsadad',
boardId: '603a4e485d99d993e0bfdfee'
}
],
scrabContent: [
{
commentsNum: 3,
likes: [],
image: [Array],
isDeleted: false,
_id: 603b67e1904622ca9ee2cddb,
title: 'ㄴㅁㅇㄹㅁㄴㄹㅁ',
content: 'ㅁㅇㄴㄹㅁㄹㅁㄴㄹㅁㄴㄹ',
postUser: 'umpa',
postUserId: 603751786587acfbf1052d34,
boardId: 603a4e485d99d993e0bfdfee,
time: '2021/02/28 18:52:32',
__v: 0
},
{
commentsNum: 5,
likes: [Array],
image: [Array],
isDeleted: false,
_id: 603b09f509dcb8b594c1f015,
title: '테스트',
content: 'ㅋㅋ',
postUser: 'umpa',
postUserId: 603751786587acfbf1052d34,
boardId: 603a4e485d99d993e0bfdfee,
time: '2021/02/28 12:11:47',
__v: 0
}
],
songs: [
{
id: '1469319400',
type: 'songs',
href: '/v1/catalog/kr/songs/1469319400',
attributes: [Object],
name: 'LOVE AGAIN'
},
{
id: '1265893529',
type: 'songs',
href: '/v1/catalog/kr/songs/1265893529',
attributes: [Object],
name: 'Get You (feat. Kali Uchis)'
},
{
id: '1265893532',
type: 'songs',
href: '/v1/catalog/kr/songs/1265893532',
attributes: [Object],
name: 'Best Part (feat. H.E.R.)'
},
{
id: '1356070221',
type: 'songs',
href: '/v1/catalog/kr/songs/1356070221',
attributes: [Object],
name: 'Daniel'
},
{
id: '1438474485',
type: 'songs',
href: '/v1/catalog/kr/songs/1438474485',
attributes: [Object],
name: 'Falling'
}
],
songsView: 0,
_id: 603a84d9760444a652d2cc72,
email: 'test',
password: '$2b$10$w8b85O6KQwGIZ0D1x0TGle.qofoEC43OKI5cMSf7tfqld12fSUWlu',
name: 'test',
__v: 0
}
and this is server code to pull. req.user._id means User Schema's _id(in this case: 603a84d9760444a652d2cc72). and req.params.id means Content _id(in this case: 603b67e1904622ca9ee2cddb) in ScrabContent.
router.delete('/deleteScrabContent/:id', requireAuth, async (req, res) => {
try {
await User.findOneAndUpdate({_id: req.user._id}, {$pull: {scrabContent: {_id: req.params.id}}}, {new: true});
} catch (err) {
return res.status(422).send(err.message);
}
});
i don't know why scrabContent doesn't work.. help me T^T

Doubts on Mongodb query

I was designing a classifieds web app with the MERN stack. The MongoSchema is as shown below
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
books: [{
title: { type: String },
author: { type: String },
desc: { type: String },
price: { type: String },
image: { data: Buffer, contentType: String }
}],
date: {
type: Date,
default: Date.now
}
});
So all the other info except the books[] will be available after the initial sign-up, but what I want to do is to update the books array every time the user wishes to post a book for selling.
I'm planning to find the user by id, but I'm not quite sure how to add/append the info to the books array.
There are some answers to your question already in Stackoverflow.
For example:
Using Mongoose / MongoDB $addToSet functionality on array of objects
You can do something like this:
UserModel.js
const mongoose = require("mongoose");
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
books: [{
title: { type: String },
author: { type: String },
desc: { type: String },
price: { type: String },
image: { data: Buffer, contentType: String }
}],
date: {
type: Date,
default: Date.now
}
});
module.exports = User = mongoose.model("user", userSchema);
After that, in your router file you can try something like this for the books array:
const res = await User.updateOne({ email: 'gintama#bandainamco.com' }, {'$addToSet':{
'books':{
title: "Gintama: The Final",
author: "Sorachi",
desc: "Final Arc",
price: "44.99",
image: "src"
}}); //addToSet if you don't want any duplicates in your array.
OR
const res = await User.updateOne({ email: 'gintama#bandainamco.com' }, {'$push':{
'books':{
title: "Gintama: The Final",
author: "Sorachi",
desc: "Final Arc",
price: "44.99",
image: "src"
}}); //push if duplicates are okay in your array