Mongoose opposite populate an array - node.js

A list could have many items. I can easily retrieve all the items from a list but I'm having issues doing the opposite i.e retrieving all lists which contain an item
ItemSchema:
const ItemSchema = mongoose.Schema({
name: { type: String, required: true, min: 1 },
created_at: { type: Date, default: Date.now }
},{ toJSON: { virtuals: true }});
ListSchema:
const ListSchema = mongoose.Schema({
title: { type: String, required: true, max: 100 },
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
description: { type: String, required: true },
items: [{
type: mongoose.Schema.Types.Mixed, ref: 'Item', quantity: 'String'
}],
completed: { type: Boolean, default: false },
date: { type: Date, default: Date.now },
});
Document:
"items": [
{
"_id": "5c6d74a98a3f532b4c1d2a23",
"quantity": "7"
}
],
How I populate: Item.findById(id).populate('lists'); but it returns empty array.
Any suggestions?

Haven't used MongoDB in a long time, but it doesn't seem you have "lists" key in your Item Schema to populate in the first place. Maybe you should add one or query the lists that have that item.

Related

How to 'join' or populate an array

Here is my very basic product schema:
const productSchema = new Schema({
productName: {
type: String,
required: true,
},
productDescription: {
type: String,
},
productPrice: {
type: Number,
},
});
module.exports = mongoose.model("Product", productSchema);
These products are listed out and a user can add a quantity for each. I am storing in an array of objects as per below. I want to join these two collections together so that I can output the qty of products selected by the user. I believe I need to use populate here but not sure how to set up the Refs and so on.
const PartySchema = new Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
catering: [{ id: mongoose.Types.ObjectId, qty: Number }],
created_at: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Party", PartySchema);
I'm sharing this solution with the assumption that the catering field is the sub-document array pointing to the Product Schema:
The Product Schema is fine so it stays the same (although to keep to convention I would advice naming your schema 'Products' instead of 'Product', Mongo Naming Covention):
const productSchema = new Schema({
productName: {
type: String,
required: true,
},
productDescription: {
type: String,
},
productPrice: {
type: Number,
},
});
module.exports = mongoose.model("Products", productSchema);
And next the Party Schema would be:
const PartySchema = new Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
catering: [{
id: {
type: mongoose.Types.ObjectId,
ref: 'Products',
},
qty: {
type: Number,
}
}],
created_at: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Parties", PartySchema);

mongoose index don't create

I tried to create index from two fields in mongoose Schema but it didn't work
this two fields are the id of two other schema and i want to be unique
i get the ids from "mongoose.Schema.ObjectId"
this is my code:
const reviewSchema = new mongoose.Schema(
{
review: {
type: String,
required: [ true, 'Review can not be empty!' ],
},
rating: {
type: Number,
min: 1,
max: 5,
},
createdAt: {
type: Date,
default: Date.now,
},
tour: {
type: mongoose.Schema.ObjectId,
ref: 'Tour',
required: [ true, 'Review must belong to a tour.' ],
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: [ true, 'Review must belong to a user' ],
},
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
},
);
reviewSchema.index({ tour: 1, user: 1 }, { unique: true });
I found it was a bug from atlas ,I don't know why but it couldnt create index with options
I create a local data base and now it works

How to limit one field only in mongoose

I am creating something like fb... I want to show 3 comments only on home page... How to limit one field only... my schema is this:
const postSchema = new Schema({
admin: { type: Types.ObjectId, ref: 'users', required: true },
text: { type: String, required: true },
comments: [{
postId: { type: Types.ObjectId, ref: 'posts', required: true },
admin: { type: Types.ObjectId, ref: 'users', required: true },
comment: { type: String, required: true },
time: { type: Date, default: Date.now }
}],
createdAt: { type: Date, default: Date.now },
modified: { type: Boolean, default: false }
});
I have all comments in an array... I want to limit them... Please help
Try using $slice (projection) in MongoDB. The $slice operator controls the number of items of an array that a query returns.
If you want to fetch first 3 comments only then your query will be as below:
db.slice.find( {}, { comments: { $slice: 3 } } )
In case if you want last 3 comments then your query will be:
db.slice.find( {}, { comments: { $slice: -3 } } )

Save to mongDB 3rd level nested array of objects

I am trying to save data into a teams database with the following model sample. This is a 3rd level nested Array of Objects for MongoDB using Mongoose.
const teamSchema = new Schema({
name: {
type: String,
required: true
},
who: {
type: String,
required: true
},
textManifesto: {
type: String,
required: false
},
videoManifesto: {
type: String,
required: false
},
competencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: true
}]
},
members: [{
member: {
type: Schema.Types.ObjectId,
ref: 'Applicant',
required: true
},
position: {
type: String,
required: true
},
memberCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: true
}]
},
evaluatedCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: false
}]
}
}],
},
I basically used push method to push the array elements into a variable and then try to save into the database but the database comes up empty for Members.memberCompetencies. It just shows and empty array.
//Map Team Competencies
for (let competency of teamCompetencies) //array is your array variable, i suppose
newTeamCompetencies.push({ competency: competency, _id: mongoose.Types.ObjectId() });
//console.log(newTeamCompetencies);
//Map My Competencies
for (let competency of myCompetencies) //array is your array variable, i suppose
newMyCompetencies.push({ _id: mongoose.Types.ObjectId(), competency: competency });
// console.log(newMyCompetencies);
team = await new Team({
name: teamName,
textManifesto: textManifesto,
who: who,
});
//save collective expected competencies of team
team.competencies = newMyCompetencies;
//save member details
team.members = ({
member: res.locals.applicant._id,
position: 'Leader',
memberCompetencies: newMyCompetencies,
})
team = await team.save();
console.log(team.members);
Expected result
[{"memberCompetencies":{ '0':
{ _id: 5d1e128b2a9f1c74907e5ba9,
competency: '5d1dd97206660707754eefb3' },
'1':
{ _id: 5d1e128b2a9f1c74907e5baa,
competency: '5d1dd9d506660707754eefb4' } },,"evaluatedCompetencies":{"competency":[]},"_id":"5d1e1393f640587531b0fd48","member":"5d19999df6f9c678e891af14","position":"Leader"}]
Actual result
[{"memberCompetencies":{"competency":[]},"evaluatedCompetencies":{"competency":[]},"_id":"5d1e1393f640587531b0fd48","member":"5d19999df6f9c678e891af14","position":"Leader"}]
Found the problem. The model was wrong. Members section of the model should be
members: {
member: {
type: Schema.Types.ObjectId,
ref: 'Applicant',
required: true
},
position: {
type: String,
required: true
},
memberCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: true
}]
},
evaluatedCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: false
}]
}
},
It should be
members: {...}
NOT
members: [{...}]

Mongoose Populate Virtuals

How to populate array of objects not by _id? I need it because I use "market_hash_name" as id in my project and it's more effectively then use _id:
let schema = new mongoose.Schema({
steamid: {
type: String,
unique: true,
index: true,
required: true
},
inventory: [{
market_hash_name: String,
name: String,
assetid: {
type: String
},
instanceid: {
type: String,
default: '0'
},
contextid: {
type: String,
default: '2'
},
amount: {
type: Number,
default: 1
},
ongoing_price_manipulation: {
type: Boolean
},
price: {
type: Number
}
}]
});
I used virtuals but only for a separate model and it works:
schema.virtual('item_data', {
ref: 'Steamlytics',
localField: 'market_hash_name',
foreignField: 'market_hash_name'
});
this.find(query).populate("item_data").exec((err, items) => {});

Resources