I have a Shop Model
const Shop = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
shop_name: { type: String },
products: {_id: mongoose.Schema.Types.ObjectId,type:Array},
});
and a product schema
const Product = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
title: { type: String },
description: { type: String },
shop: { type: mongoose.Schema.Types.ObjectId, ref: "Shop" },
});
I'm trying to access a product within the products array of the Shop model, so that I can update it.
I've looked online a lot but couldn't quite find what I'm looking for. I need to access a very specific product within the products array with the given parameters, which are the id of the shop and the id of the product.
This is what I tried to do
const item = await Product.findOne({_id} , 'products').find({"products._id" : productId})
But what this does is it gives a mongoose object if the second find method hits a match
[
{
products: [ [Object] ],
_id: 617f1bca39a5a43c1a981060,
butik: 'scsbutik',
butik_slug: 'egzbutikcom-1000010',
butik_image: 'https://webizade.com/bm/img/butik-10.jpg',
butik_points: '9.8',
butik_order_count: 45,
butik_success_order_count: 42,
butik_refund_count: 3,
is_butik_refund: true,
__v: 0,
login: []
}
]
I need to access the object INSIDE the products array and update that product.
Appreciate any help in advance.
don't use by default _id format I suggest declare a different value and then using populate method you can do it
const Product = mongoose.Schema({
shopId: mongoose.Schema.Types.ObjectId,
title: { type: String },
description: { type: String },
shop: { type: mongoose.Schema.Types.ObjectId, ref: 'Shop' },
});
THEN ROUTING
const item = await Product.find(_id).populate('shopId')
Related
I have two mongodb model as following.
const CompanySchema = new Schema(
{
sections: [{
name: { type: String },
budgets: [{ // indicates from CalcSchema
index: { type: Number },
title: { type: String },
values: [Number],
sum: { type: Number, default: 0 },
}],
}]
},
{ timestamps: true }
);
const CalcSchema = new Schema({
budget: {
type: Schema.Types.ObjectId, // I want to populate this field. this indicates budget document in Company model
ref: "Company.sections.budgets" //it's possible in mongoose?
},
expense: {
type: Number,
default: 0
}
});
budget field indicate one of budgets field in CompanySchema.
So I want to populate when get Calc data.
But I don't how to populate embedded document.
I tried set ref value to ref: "Company.sections.budgets". but it's not working.
Please anyone help.
Finally, I found answer myself.
There is useful plugin for it.
https://github.com/QuantumGlitch/mongoose-sub-references-populate#readme
And I learned that my schema structure was wrong. It's anti-pattern in mongodb.
This is my category schema. For every category document, there is a subdocument of subcategories
#category schema
const CategorySchema = mongoose.Schema({
name: {
type: String, required: true
},
subcategories: [{
name: {
type: String, required: false
},
}],
created : {
type : Date,
default: Date.now()
}
});
let Categories = mongoose.model('categories', CategorySchema);
# selected category schema
const BusinessCategoriesSchema = mongoose.Schema({
business_id: {
type: String
},
category_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "categories",
required: true
},
subcategories: [{
subcategory_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "subcategories._id",
required: false
}
}]
});
let businessCategories = mongoose.model('business-categories', BusinessCategoriesSchema);
How can I retrieve the subcategories sub-document from Categories schema when I perform a query on business-categories collection?
#This is the code snippet I am using but am not getting my desired result
const query = await businessCategories.find({business_id : businessId })
.populate('category_id')
.populate('subcategories.subcategories_id');
I know I am not doing something right.
I was able to get the category name from categories schema but I could not get the subcategories sub-document from the categories schema.
Thank you in advance
I have two models Vote and Link,I am trying to populate the votes array in link model,The votes array contains id's that references to the collection Vote,which only contains two fields link and User which also refs to same link model mentioned below and a user model respectively
link Schema:-
const linkSchema = new mongoose.Schema(
{
description: {
type: String,
trim: true,
},
url: {
type: String,
trim: true,
},
postedBy: {
type: mongoose.Types.ObjectId,
ref: "User",
},
votes: [{ type: mongoose.Types.ObjectId, ref: "Vote" }],
},
{
timestamps: true,
}
);
linkSchema.index({ description: "text" });
linkSchema.index({ createdAt: -1 });
module.exports = mongoose.model("Link", linkSchema);
Vote schema:-
const mongoose = require("mongoose");
const voteSchema = new mongoose.Schema({
link: { type: mongoose.Types.ObjectId, ref: "Link" },
user: { type: mongoose.Types.ObjectId, ref: "User" },
});
module.exports = mongoose.model("Vote", voteSchema);
but when i try to get the votes of a link,it always return an empty array ,My function:-
const votes = async ({ id }) => {
const linkData = await Link.findById(id).populate("votes").exec();
console.log(linkData);
};
Output Data:-
{
votes: [], //empty always
_id: 5ecb21059a157117c03d4fac,
url: 'https://www.apollographql.com/docs/react/',
description: 'The best GraphQL client for React',
postedBy: 5ec92a58bf38c32b38400705,
createdAt: 2020-05-25T01:36:05.892Z,
updatedAt: 2020-05-25T01:37:52.266Z,
__v: 0
}
Instead of populate(), you can use aggregate() to get your desired output. This should probably work in your case:
Link.aggregate([
{
$match: {
_id: { $in: [mongoose.Types.ObjectId(id)] // as suggested by the questioner
}
},
{
$lookup: {
from: "vote", // collection to join
localField: "votes", // field from the input documents (filtered after _id is matched)
foreignField: "link", // field to compare with, from other collection
as: "linkData" // output array name
}
}
])
Let me know in the comments.
I m trying to populate a mongoose model where I only want the returned items to be the ones that are matched with an ID.
Edit update: In the User model below, I need to first find the correct user by id, then for the task property, I need to populate it where the projectID matches req.params.ID. How can I only populate the tasks where the projectID matches the req.params.ID. I have included my full User model as well as the Task model
//User Schema
var UserSchema = new Schema({
name: {
type: String,
trim: true,
required: "First Name is Required"
},
username: {
type: String,
trim: true,
required: "Username is Required"
},
skills: {
type: String,
trim : true
},
avatar: {
type: String
},
SQLid: {
type: Number
},
userCreated: {
type: Date,
default: Date.now
},
lastUpdated: {
type: Date
},
adminTeams: [{
type: Schema.Types.ObjectId,
ref: "Team"
}],
team: [{
type: Schema.Types.ObjectId,
ref: "Team"
}],
task: [{
projectID: {
type: String
},
theTask: {
type: Schema.Types.ObjectId,
ref: "Task"
}
}]
});
//Task Schema
var TodoSchema = new Schema({
task: {
type: String
}
});
How can I only get the task populated where the projectID is equal to a specific ID. I tried
User.findById({ "_id": req.params.id }).populate({ path: 'task', match: {projectID: req.params.pID}, select: 'theTask' })
.exec(function(err, docs){
console.log("POPULATE TASKS DOCS", docs)
But this is showing that the docs is empty.
you can use $elemMatch ,it will give you all those docs which matches your projectId and populate your task document .
So the query would be -
var query={
task:{
$elemMatch:{
projectId: req.params.id
}
}
}
User.find(query)
.populate('theTask')
.select('theTask') // use for getting selective data from document
.exec(function(){}) //your callback fuction
Hope I answer your question.
Thanks.
In your task schma you have kept the type of the task type as string and in your user schema the theTask have the refrence of the task and task its Self is just a string . Thats why it is not being populated ..
So change the task schema to (Keep it simple)-
var Task= new Schema({
name :string
});
Populate need refrence Id to get the whole document
var SecuritySchema = new Mongoose.Schema({
_bids: [{
type: Mongoose.Schema.Types.ObjectId,
ref: 'BuyOrder'
}],
_asks: [{
type: Mongoose.Schema.Types.ObjectId,
ref: 'SellOrder'
}]
});
var OrdersSchema = new Mongoose.Schema({
_security: {
type: Mongoose.Schema.Types.ObjectId,
ref: 'Security'
},
price: {
type: Number,
required: true
},
quantity: {
type: Number,
required: true
}
});
// declare seat covers here too
var models = {
Security: Mongoose.model('Security', SecuritySchema),
BuyOrder: Mongoose.model('BuyOrder', OrdersSchema),
SellOrder: Mongoose.model('SellOrder', OrdersSchema)
};
return models;
And than when I save a new BuyOrder for example:
// I put the 'id' of the security: order.__security = security._id on the client-side
var order = new models.BuyOrder(req.body.order);
order.save(function(err) {
if (err) return console.log(err);
});
And attempt to re-retrieve the associated security:
models.Security.findById(req.params.id).populate({
path: '_bids'
}).exec(function(err, security) {
// the '_bids' array is empty.
});
I think this is some sort of naming issue, but I'm not sure, I've seen examples here and on the moongoose website that use Number as the Id type: http://mongoosejs.com/docs/populate.html
The ref field should use the singular model name
Also, just do:
models.Security.findById(req.params.id).populate('_bids').exec(...
My main suspicion given your snippet at the moment is your req.body.order has _security as a string instead of an array containing a string.
Also, you don't need an id property. Mongodb itself will automatically do the _id as a real BSON ObjectId, and mongoose will add id as a string representation of the same value, so don't worry about that.
While I don't understand your schema (and the circular nature of it?), this code works:
var order = new models.BuyOrder({ price: 100, quantity: 5});
order.save(function(err, orderDoc) {
var security = new models.Security();
security._bids.push(orderDoc);
security.save(function(err, doc) {
models.Security.findById({ _id: doc._id })
.populate("_bids").exec(function(err, security) {
console.log(security);
});
});
});
It:
creates a BuyOrder
saves it
creates a Security
adds to the array of _bids the new orderDoc's _id
saves it
searches for the match and populates
Note that there's not an automatic method for adding the document to the array of _bids, so I've done that manually.
Results:
{ _id: 5224e73af7c90a2017000002,
__v: 0,
_asks: [],
_bids: [ { price: 100,
quantity: 5,
_id: 5224e72ef7c90a2017000001, __v: 0 } ] }