Need help in writing an aggregate query - node.js

I want only that data in "present" which is matched with student _id. But for now by this query I'm getting all student counts in every individual students data.
Student Schema
const StudentSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, "Please Provide Name"],
maxlength: 100,
minlength: 2,
},
email: {
type: String,
required: [true, "Please Provide Email"],
match: [
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
"Please Provide a Valid Email",
],
unique: true,
},
number: {
type: String,
required: [true, "Please Provide Number"],
match: [
/^(?:(?:\+|0{0,2})91(\s*[\-]\s*)?|[0]?)?[789]\d{9}$/,
"Please Provide a Valid Number",
],
unique: true,
},
rollNumber: {
type: Number,
required: [true, "Please Provide Roll Number"],
maxlength: 5,
},
departmentID: {
type: mongoose.Types.ObjectId,
ref: "Department",
required: [true, "Please Provide departmentID"],
},
classID: {
type: mongoose.Types.ObjectId,
ref: "Class",
required: [true, "Please Provide classID"],
},
position: {
type: String,
required: [true, "Please Provide Position"],
enum: ["Student"],
default: "Student",
},
password: {
type: String,
required: [true, "Please Provide Password"],
minlength: 6,
},
},
{ timestamps: true }
);
Attendance Schema
const mongoose = require("mongoose");
const { Schema } = mongoose;
const AttendanceSchema = new Schema(
{
date: {
type: String,
required: [true, "Please Provide Date"],
maxlength: 15,
minlength: 5,
},
subjectID: {
type: mongoose.Types.ObjectId,
ref: "Subject",
required: [true, "Please Provide Subject"],
},
studentID: [
{
type: mongoose.Types.ObjectId,
ref: "Student",
required: [true, "Please Provide Student"],
},
],
teacherID: {
type: mongoose.Types.ObjectId,
ref: "Faculty",
required: [true, "Please Provide Teacher"],
},
classID: {
type: mongoose.Types.ObjectId,
ref: "Class",
required: [true, "Please Provide Class"],
},
departmentID: {
type: mongoose.Types.ObjectId,
ref: "Department",
required: [true, "Please Provide Department"],
},
},
{ timestamps: true }
);
module.exports = mongoose.model("Attendance", AttendanceSchema);
The Query I'm Writing
await StudentSchema.aggregate([
{
$match: {
classID: mongoose.Types.ObjectId(`${req.params.id}`),
},
},
{
$project: { createdAt: 0, updatedAt: 0, __v: 0, password: 0 },
},
{
$lookup: {
from: "attendances",
pipeline: [
{
$match: {
subjectID: mongoose.Types.ObjectId(`${req.params.Sid}`),
},
},
{ $unwind: "$studentID" },
{ $group: { _id: "$studentID", count: { $sum: 1 } } },
],
as: "present",
},
},
Data I'm Getting From This Query
{
"subject1": [
{
"_id": "635d40803352895afffdc294",
"name": "D R",
"email": "dugu#gmail.com",
"number": "9198998888",
"rollNumber": 202,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635d40803352895afffdc294",
"count": 3
},
{
"_id": "635eb8898dea5f437789b751",
"count": 2
}
]
},
{
"_id": "635eb8898dea5f437789b751",
"name": "V R",
"email": "v#gmail.com",
"number": "9198998899",
"rollNumber": 203,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635d40803352895afffdc294",
"count": 3
},
{
"_id": "635eb8898dea5f437789b751",
"count": 2
}
]
}
]
}
This type of data I'm trying to achieve. Only that data which will be matched with _id in present array.
{
"subject1": [
{
"_id": "635d40803352895afffdc294",
"name": "D R",
"email": "dugu#gmail.com",
"number": "9198998888",
"rollNumber": 202,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635d40803352895afffdc294",
"count": 3
}
]
},
{
"_id": "635eb8898dea5f437789b751",
"name": "V R",
"email": "v#gmail.com",
"number": "9198998899",
"rollNumber": 203,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635eb8898dea5f437789b751",
"count": 2
}
]
}
]
}

You can just use the let option in the $lookup and pass the studentId, then you could match the proper attendances as part of the $lookup stage, like so:
{
$lookup: {
from: "attendances",
let: {
studentID: "$_id"
},
pipeline: [
{
$match: {
subjectID: 2,
$expr: {
$eq: [
"$$studentID",
"$studentID"
]
}
}
},
{
$unwind: "$studentID"
},
{
$group: {
_id: "$studentID",
count: {
$sum: 1
}
}
}
],
as: "present"
}
}
Mongo Playground
Another alternative would be to filter out the present array at the end but that would be less efficient and will uglify the code.

Related

How can I filter data based on populated fields

Product Schema
const ProductSchema = new mongoose.Schema(
{
name: {
type: String,
trim: true,
required: [true, "Please provide product name"],
maxlength: [100, "Product name cannot be more than 100 characters"],
minlength: [5, "Product name cannot be less than 10 characters"],
},
description: {
type: String,
required: [true, "Please provide product description"],
maxlength: [
1000,
"Product description cannot be more than 1000 characters",
],
},
price: {
type: Number,
required: [true, "Please provide product price"],
min: [100, "Minimum price of a product cannot be less than 100"],
},
discountPercentage: {
type: Number,
default: 0,
min: [
0,
"You cannot provide discount percentage of a product less than 0.",
],
},
category: {
type: mongoose.Schema.ObjectId,
ref: "Category",
},
brand: {
type: mongoose.Schema.ObjectId,
ref: "Brand",
},
stock: {
type: Number,
required: false,
default: 15,
},
rating: {
type: Number,
default: 4.5,
min: [1, "Rating must be above 1.0"],
max: [5, "Rating must be below 5.0"],
set: (value) => Math.round(value * 10) / 10,
},
numberOfReviews: {
type: Number,
default: 0,
},
thumbnail: {
type: String,
required: [true, "Please provide thumbnail for your product"],
},
images: {
type: [String],
required: false,
},
seller: {
type: mongoose.Schema.ObjectId,
ref: "User",
},
active: {
type: Boolean,
default: true,
},
slug: {
type: String,
default: function () {
return slugify(this.name, { lower: true });
},
},
},
{
timestamps: true,
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
Document without populated fields
{
"discountPercentage": 5.92,
"category": "5c8a38c714eb5c17645c911b",
"brand": "5c8a3abc14eb5c17645c9128",
"stock": 44,
"rating": 5,
"numberOfReviews": 0,
"images": [
"https://dummyjson.com/image/i/products/98/1.jpg",
"https://dummyjson.com/image/i/products/98/2.jpg",
"https://dummyjson.com/image/i/products/98/3.jpg",
"https://dummyjson.com/image/i/products/98/4.jpg",
"https://dummyjson.com/image/i/products/98/thumbnail.jpg"
],
"seller": 62dd1a1ace415b229452393e",
"active": true,
"_id": "62e2d0324971c94a30715b44",
"name": "3 lights lndenpant kitchen islang",
"description": "3 lights lndenpant kitchen islang dining room pendant rice paper chandelier contemporary led pendant light modern chandelier",
"price": 34,
"thumbnail": "https://dummyjson.com/image/i/products/98/thumbnail.jpg",
"slug": "3-lights-lndenpant-kitchen-islang",
"createdAt": "2022-07-28T18:06:43.006Z",
"updatedAt": "2022-07-28T18:06:43.006Z",
"discountedPrice": 32,
"id": "62e2d0324971c94a30715b44"
},
Document with populated fields (brand and category)
{
"discountPercentage": 5.92,
"category": {
"_id": "5c8a38c714eb5c17645c911b",
"name": "lighting",
"slug": "lighting"
},
"brand": {
"_id": "5c8a3abc14eb5c17645c9128",
"name": "dadawu",
"slug": "dadawu"
},
"stock": 44,
"rating": 5,
"numberOfReviews": 0,
"images": [
"https://dummyjson.com/image/i/products/98/1.jpg",
"https://dummyjson.com/image/i/products/98/2.jpg",
"https://dummyjson.com/image/i/products/98/3.jpg",
"https://dummyjson.com/image/i/products/98/4.jpg",
"https://dummyjson.com/image/i/products/98/thumbnail.jpg"
],
"seller": "62dd1a1ace415b229452393e",
"active": true,
"_id": "62e2d0324971c94a30715b44",
"name": "3 lights lndenpant kitchen islang",
"description": "3 lights lndenpant kitchen islang dining room pendant rice paper chandelier contemporary led pendant light modern chandelier",
"price": 34,
"thumbnail": "https://dummyjson.com/image/i/products/98/thumbnail.jpg",
"slug": "3-lights-lndenpant-kitchen-islang",
"createdAt": "2022-07-28T18:06:43.006Z",
"updatedAt": "2022-07-28T18:06:43.006Z",
"discountedPrice": 32,
"id": "62e2d0324971c94a30715b44"
},
I'm using a middleware to populate all fields whenever a request is made to an API
ProductSchema.pre(/^find/, function (next) {
this.populate({
path: "category",
select: "name _id slug",
}).populate({
path: "brand",
select: "name _id slug -categories",
});
next();
});
My question is that how can I filter the data based on populated fields.
For example: If I want to filter data based on category and brand, /products?catergory=smartphones&brand=apple
How to fulfill the above condition?
Mongoose version: ^5.13.14

MongoDB: How to aggregate and $group then filter specific date

Employee Schema
const employeeSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid');
}
},
},
password: {
type: String,
required: true,
trim: true,
minLength: 6,
validate(value) {
if (value.toLowerCase().includes('password')) {
throw new Error("Password can not contain a word 'password'.");
}
},
},
birthdate: {
type: Date,
required: true,
},
cellphone: {
type: String,
required: true,
trim: true,
},
gender: {
type: String,
enum: ['남성', '여성'],
required: true,
},
hourly_wage: {
type: Number,
trim: true,
default: 0,
},
timeClocks: [
{
type: new mongoose.Schema({
start_time: {
type: Date,
required: true,
},
end_time: {
type: Date,
},
wage: {
type: Number,
required: true,
},
total: {
type: Number,
},
totalWorkTime: {
type: Number
}
}),
},
],
role: {
type: String,
enum: ['staff'],
default: 'staff',
},
stores: [
{
location: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Location',
},
},
],
status: {
//현재 재직상태
type: String,
enum: ['재직자', '퇴직자'],
default: '재직자',
},
tokens: [
{
token: {
type: String,
required: true,
},
},
],
},
{
timestamps: true,
}
);
What I have done so far
const employees = shifts.map((d) => d.owner._id);
//timeclock
const temp = await Employee.aggregate([
{
$match: {
_id: { $in: employees },
},
},
{
$sort: { 'timeClocks.start_time': 1 },
},
{
$unwind: { path: '$timeClocks', preserveNullAndEmptyArrays: true },
},
{
$group: {
_id: '$_id',
name: { $first: '$name' },
timeClock: {
$push: '$timeClocks',
},
},
},
]);
My result
{
"shifts": [
{
"_id": "60e05b188be53900280bcdf2",
"date": "2021-07-09T00:00:00.000Z",
"day": "Fri",
"start": "2021-07-09T09:41:00.000Z",
"end": "2021-07-09T21:42:00.000Z",
"owner": {
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd"
},
"location": "60cd99b1b4ddcc00285b0df3",
"__v": 0
}
],
"timeClock": [
{
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd",
"timeClock": [
{
"_id": "60def63d19648a00286f0539",
"start_time": "2021-05-04T02:19:00.000Z",
"end_time": "2021-05-04T14:42:00.000Z",
"wage": 8720,
"total": 107735,
"totalWorkTime": 743
},
{
"_id": "60def63f19648a00286f053d",
"start_time": "2021-05-02T08:12:00.000Z",
"end_time": "2021-05-02T22:24:00.000Z",
"wage": 8720,
"total": 123540,
"totalWorkTime": 852
},
{
"_id": "60def64119648a00286f0541",
"start_time": "2021-05-10T20:14:00.000Z",
"end_time": "2021-05-10T22:17:00.000Z",
"wage": 8720,
"total": 17835,
"totalWorkTime": 123
},
}
]
Expected Result(2021-05-10)
{
"shifts": [
{
"_id": "60e05b188be53900280bcdf2",
"date": "2021-07-09T00:00:00.000Z",
"day": "Fri",
"start": "2021-07-09T09:41:00.000Z",
"end": "2021-07-09T21:42:00.000Z",
"owner": {
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd"
},
"location": "60cd99b1b4ddcc00285b0df3",
"__v": 0
}
],
"timeClock": [
{
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd",
"timeClock": {
"_id": "60def64119648a00286f0541",
"start_time": "2021-05-10T20:14:00.000Z",
"end_time": "2021-05-10T22:17:00.000Z",
"wage": 8720,
"total": 17835,
"totalWorkTime": 123
},
}
]
I am receiving the 'date string' example('URL/2021-05-10') via params and trying to query all employees that have the same date timeClocks.
also trying to send back everything I queried without different dates from timeClocks.
How can I filter out non-same dates?
You have string 2021-05-10 now you need a $match stage before your group so you can filter out timeClock. Something like:
{ $match: { 'timeClocks.start_time': new Date('2021-05-10') } }
Modify the match stage to your requirements like maybe add $gte or $lte or something like that.

Mongoose: How to query nested document and return String result?

Did a query Product.findOne({'variation.sku': req.params.productVariationSKU },{'_id': 0, 'variation.price' :1}) to find the price of a product variation.
But result returned price of all product variations. Need help to find where went wrong!
Below is product schema:
var ProductSchema = new Schema({
productId: {
type: Number,
required: [true, 'Product ID is required'],
unique: true
},
sku: String,
category: [String],
language: {
type: String,
lowercase: true,
maxlength: 2,
required: [true, 'Language code required'],
index: true,
unique: true
},
name: {
type: String,
required: [true, 'Product name is required']
},
descLong: String,
descShort: String,
mainImageURL: String,
galleryImageURL: [String],
variation: [{
sku: String,
option: [{
label: String,
value: String,
}],
inventory: [{
name: String,
quantity: Number,
country: String
}],
inStock: Boolean,
price: mongoose.Types.Decimal128
}],
attribute: [{
label: String,
value: [String]
}],
inStock: Boolean,
currencySymbol: String,
slug: String,
metaTitle: String,
metaDescription: String,
relatedAccessory: [Number],
htmlContentBefore: String,
htmlContentAfter: String
});
Below is product object from Postman:
{
"category": [],
"galleryImageURL": [
"TEST.png"
],
"relatedAccessory": [],
"_id": "5feae4418d686300176dfbbd",
"productId": 1,
"language": "en",
"name": "TEST PRODUCT",
"descLong": "<p><strong>This is a long description</strong></p>",
"descShort": "Short Description",
"mainImageURL": "TEST.png",
"variation": [
{
"option": [
{
"_id": "5feae4418d686300176dfbbf",
"label": "Color",
"value": "Black"
}
],
"inventory": [],
"_id": "5feae4418d686300176dfbbe",
"sku": "P-1",
"inStock": true,
"price": "45"
},
{
"option": [
{
"_id": "5feae4418d686300176dfbc1",
"label": "Color",
"value": "White"
}
],
"inventory": [],
"_id": "5feae4418d686300176dfbc0",
"sku": "P-2",
"inStock": true,
"price": "45"
}
],
"attribute": [
{
"value": [
"Black",
"White"
],
"_id": "5feae4418d686300176dfbc2",
"label": "Color"
}
],
"currencySymbol": "£",
"slug": "test",
"metaTitle": "testmeta",
"metaDescription": "This is meta description",
"__v": 0
}
Below is API function:
app.get('/API/Product/GetProductVariationPrice/:productVariationSKU', async(req, res) => {
try{
res.send(await Product.findOne({'variation.sku': req.params.productVariationSKU },{'_id': 0, variation :1}));
} catch (err) {
res.status(500).send(err);
}
});
Returned result from Postman:
{
"variation": [
{
"price": "45"
},
{
"price": "45"
}
]
}
Question: How can I get just "45" of variation SKU "P-1"? As the result currently returns the price of variation 'P-2' as well which is not wanted. SKU should be based on the param passed to the API.
Generally it will return array of object when we project specific field from array of object,
Starting in MongoDB 4.4, as part of making find projection consistent with aggregation’s $project stage,
$reduce to iterate loop of variation array, check condition if sku match then it will return price
await Product.findOne(
{ "variation.sku": req.params.productVariationSKU },
{
"_id": 0,
variation: {
$reduce: {
input: "$variation",
initialValue: 0,
in: {
$cond: [
{ $eq: ["$$this.sku", req.params.productVariationSKU] },
"$$this.price",
"$$value"
]
}
}
}
})
Playground
MongoDB 4.4 or below versions try aggregate(),
let p = Product.aggregate();
p.match({ "variation.sku": req.params.productVariationSKU });
p.project({
_id: 0,
variation: {
$reduce: {
input: "$variation",
initialValue: 0,
in: {
$cond: [
{ $eq: ["$$this.sku", req.params.productVariationSKU] },
"$$this.price",
"$$value"
]
}
}
}
});
res.send(await p.exec());
Playground

$lookup not working whle using on _id field in mongodb(mongoose) [duplicate]

This question already has answers here:
Mongoose always returning an empty array NodeJS
(7 answers)
Querying after populate in Mongoose
(6 answers)
Closed 4 years ago.
I have two models, user and schedule, and i want to combine these two using $lookup and mongoose.
User (model)
name: {
type: String,
required: true
},
firstName: {
String
},
lastName: {
String
},
storeKey: {
type: String,
required: true
},
avatar: String,
birthday: String,
phone: {
type: String
},
doc: String,
email: {
type: String
},
password: {
passwordHash: String,
salt: String
},
active: {
type: Boolean,
default: true
},
deleted: {
type: Boolean,
default: false
},
generalObservations: {
type: String
},
from: {
type: String
},
services: {
type: Number,
default: 0
},
no_shows: {
type: Number,
default: 0
},
// campos para integração
integrationId: String
}, {
timestamps: true
Schedule (model)
store: {
type: String,
required: true
},
customer: {
id: {
type: ObjectId
},
name: {
type: String,
required: true
},
avatar: String,
phone: {
type: String
},
doc: {
type: String
},
},
employee: {
id: {
type: String,
required: true
},
name: {
type: String,
required: true
},
avatar: String,
},
service: {
id: {
type: String
},
name: {
type: String,
required: true
},
filters: [String]
},
info: {
channel: {
type: String,
required: true,
default: 'app'
},
id: String,
name: String
},
scheduleDate: {
type: String,
required: true
},
scheduleStart: {
type: String,
required: true
},
scheduleEnd: {
type: String,
required: true
},
value: {
type: Number,
required: true
},
comissionType: {
type: String,
default: '$'
},
comissionValue: {
type: Number,
default: 0
},
status: {
type: Number,
required: true
},
observation: String,
paymentMethod: {
type: Number,
default: 0
},
paymentValue: String,
paymentChange: String
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
And now my query using mongoose:
User aggregate
User.aggregate([{
$match: {
storeKey: req.body.store,
}
},
{
$group: {
_id: {
id: "$_id",
name: "$name",
cpf: "$cpf",
phone: "$phone",
email: "$email",
birthday: "$birthday"
},
totalServices: {
$sum: "$services"
}
}
},
{
$lookup: {
from: "schedule",
localField: "_id.id",
foreignField: "customer.id",
as: "user_detail"
}
}
the result of my query is a empty array(user_detail) like this:
Result of the query:
{
"_id": {
"id": "5bdb5b16ee9b7a4aa810bc62",
"name": "Jonas com aniversário",
"phone": "11984798494",
"email": "j#jz.com",
"birthday": "Thu Nov 01 2018 16:59:18 GMT-0300 (Hora oficial do Brasil)"
},
"totalServices": 0,
"user_detail": []
}
I don't know why, but the query result is a empty array and i was trying to using $unwind and $match but doesn't work too.
EDIT:
Collection of user
{
"_id": "5b1b1dcce1ab9a12a8eb580f",
"password": {
"salt": "d095f2",
"passwordHash": "b24881ef4c43d28e93bcff5da2ce32e4287aabf77540d2465482a435a5929a63f2ba9fb7e1cc14fa4e8183d83e33854ec6153fbbb872e65a9e3f188892bf56cc"
},
"name": "Anderson Zanardi",
"cpf": "31933765828",
"phone": "11996370565",
"birthday": "1984-03-18",
"email": "dev#wabiz.com.br",
"storeKey": "5b16cceb56a44e2f6cd0324b",
"createdAt": "2018-06-09T00:22:36.464Z",
"updatedAt": "2018-11-06T13:51:37.261Z",
"__v": 0,
"doc": "31933765828",
"active": true,
"from": "app",
"deleted": false,
"services": 80
},
Collection of schedule
{
"_id": "5b1c20d8fc76f904849712c9",
"customer": {
"id": "789456",
"name": "Gabriel Barreto",
"phone": "11995274098",
"cpf": "40735255814"
},
"employee": {
"id": "5b16cebd29bcf613f02b6fb4",
"name": "Anderson Zanardi",
"avatar": ""
},
"service": {
"filters": [
"corte_simples",
"corte_masculino"
],
"id": "service_id",
"name": "Corte Masculino"
},
"store": "5b16cceb56a44e2f6cd0324b",
"scheduleDate": "2018-06-07",
"scheduleStart": "2018-06-28 13:00",
"scheduleEnd": "2018-06-28 13:30",
"status": 1,
"value": 50,
"created": "2018-06-09T18:47:52.862Z",
"updated": "2018-06-09T18:47:52.862Z",
"__v": 0
},
Mongoose pluralize the collection name at the time of creation. So instead of schedule you should use schedules
{ "$lookup": {
"from": "schedules",
"localField": "_id.id",
"foreignField": "customer.id",
"as": "user_detail"
}}
or either import the collection and extract the collection name from it
const Schedule = require('/schedules')
{ "$lookup": {
"from": Schedule.collection.name,
"localField": "_id.phone",
"foreignField": "customer.phone",
"as": "user_detail"
}}

Collections association with nested in Mongoose

I had a problem with the association of collections.
I spent 2 days and still did not solve the problem, it's new for me.
My models:
// Schema opened cases
const openedSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user',
required: [true, 'user is required'],
index: true
},
weapon: {
type: Schema.Types.ObjectId,
ref: 'cases.weapons',
required: [true, 'weapon is required'],
index: true
},
sellPrice: {
type: Number,
default: null
},
status: {
type: Number,
default: 0
}
}, {
timestamps: true
});
const opened = mongoose.model('opened', openedSchema);
// list cases
const casesSchema = new Schema({
name: {
type: String,
unique: true,
required: [true, 'name is required']
},
price: {
type: Number,
required: [true, 'price is required']
},
weapons: [ {
weapon: {
type: Schema.Types.ObjectId,
ref: 'weapon',
index: true
}
} ]
}, {
timestamps: false
});
const cases = mongoose.model('cases', casesSchema);
// list weapons
const weaponSchema = new Schema({
name: {
type: String,
unique: true,
required: [true, 'name is required']
},
price: {
type: Number,
required: [true, 'price is required']
},
autoship: {
count: Number,
status: Boolean,
price: Number
}
}, {
timestamps: false
});
const weapon = mongoose.model('weapon', weaponSchema);
That's what documents look like
// cases
{
"_id": {
"$oid": "59653bcfa9ac622e1913e10c"
},
"name": "test case #1",
"price": 256,
"weapons": [
{
"weapon": {
"$oid": "59653bcfa9ac622e1913e10b"
},
"_id": {
"$oid": "59653bcfa9ac622e1913e10d"
}
},
{
"_id": {
"$oid": "59653d3279aeda2fda9fb490"
},
"weapon": {
"$oid": "59653c5d069f562eb0ba4ef3"
}
},
{
"_id": {
"$oid": "59653d38ba04de2fdddc459f"
},
"weapon": {
"$oid": "59653c893a772e2ef7b65a29"
}
}
],
"__v": 0
}
// opened
{
"_id": {
"$oid": "5965d134c8c95972a1a498f5"
},
"updatedAt": {
"$date": "2017-07-12T07:35:16.419Z"
},
"createdAt": {
"$date": "2017-07-12T07:35:16.419Z"
},
"user": {
"$oid": "5965d0d6ea9db872360db98b"
},
"weapon": {
"$oid": "59653bcfa9ac622e1913e10d"
},
"status": 0,
"sellPrice": null,
"__v": 0
}
// weapon
{
"_id": {
"$oid": "59653bcfa9ac622e1913e10b"
},
"name": "AWP | Fever Dream",
"price": 300,
"autoship": {
"status": true,
"price": 167,
"count": 5
},
"__v": 0
}
I need to get a list of open cases with weapons data.
opened -> cases -> weapon
So, I do this:
opened.find()
.populate('cases.weapons')
.then(_opened => {
console.log(_opened);
})
.catch(err => {
logger.error(err);
});
But populate does not work.
Unless I am mistaken, there is no relationship between openedSchema and casesSchema.
It is not opened -> cases -> weapon but opened -> weapon as openedSchema has no field called cases -- which means cases will never be populated.
Based on your schema definition, it should be opened.find().populate('weapon').

Resources