Here's my schema.
const Sample = new Schema({
name: { type: String },
people: { type: Schema.Types.ObjectId, ref: 'People' }
})
const People = new Schema({
name: { type: String }
})
Now when I am trying to query the name of People schema using Sample schema.
var queryString = 'name of people'
const results = await Sample.find().populate('people').find({
'people.name': { $regex: queryString, $options: 'i' },
})
It's working if I am just querying the name of Sample schema but when I'm trying to query the name of People schema on Sample model there are no results.
Mongoose populate supports applying query conditions:
const results = await Sample.find()
.populate({path: 'people', name: {'APPLY YOUR QUERY CONDITIONS HERE'}});
Check the official documentation:
https://mongoosejs.com/docs/populate.html#query-conditions
Related
I had spent hours trying to work out how to get records from a document's child array by a specific field, but I failed it.
I would like to pass a personId by a web service to find which meeting he/she has been invited to. As a result, I could track down whether the invitee has accept to join the meeting or not.
Basically, I have the following JSON output:
{
"status": "success",
"requestedAt": "2021-03-28T22:47:03+11:00",
"size": 1,
"meetings": [
{
"invitedMembers": [
{
"isJoined": false,
"_id": "605ffbc00a21ed718c992549",
"person": "a123",
"__v": 0
}
]
}
]
}
with a controller like this:
const memberId = "a123";
const meetings = await Meeting.find({
'invitedMembers.member': memberId
}).populate('invitedMembers');
a meeting model class like below:
const mongoose = require('mongoose');
const meetingSchema = new mongoose.Schema({
invitedMembers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'InvitedMembers'
}
]
});
const Meeting = mongoose.model(
'Meeting',
meetingSchema
);
module.exports = Meeting;
and a invitedMembers class like this:
const mongoose = require('mongoose');
const invitedMembersSchmea = new mongoose.Schema({
member: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Member',
required: true
},
isJoined: {
type: Boolean,
default: false
}
});
const InvitedMembers = mongoose.model(
'InvitedMembers',
invitedMembersSchmea
);
module.exports = InvitedMembers;
The Member schema only contains a basic personal information such as first name, last name and etc.
I ended up solving my own problem by using a different approach where I changed my data structure by adding invitedMembers as an embedding model in the meeting model and updated the person field in the invitedMembers schema to _id.
Updated Meeting model class:
const mongoose = require('mongoose');
const invitedMembersSchmea = new mongoose.Schema({
_id: {
type: String,
required: true
},
isJoined: {
type: Boolean,
default: false
}
});
const meetingSchema = new mongoose.Schema({
invitedMembers: [
{
type: invitedMembersSchmea
}
]
});
const Meeting = mongoose.model(
'Meeting',
meetingSchema
);
module.exports = Meeting;
As a result, I can find the invited member by ID using the following query:
const memberId = "a123";
const meetings = await Meeting.find({
'invitedMembers._id': memberId
});
I am going to store a category id to an item.
I do the below .save() function to add a new row.
const myNewItem = {
categoryId = ObjectId("5fc0a6e58dc3892120595384"),
title = "Apple"
}
var myNewItemSave = await new Item(myNewItem).save();
However, when I check my database record
_id: ObjectId("..."),
categoryId: "5fc0a6e58dc3892120595384",
title: "Apple"
The categoryId is not saved as ObjectId.
I want to save it as ObjectId is because I am going to query some lookup aggregation like this:
https://mongoplayground.net/p/50y2zWj-bQ6
so I have to make localField and foreignField are the same type as ObjectId.
It happen becuse your schema don't allow category id as mongoose objectId it is string
const schema = new Mongoose.Schema(
{
title: { type: String },
categoryId: { type: Mongoose.Schema.ObjectId, ref: 'categories' }
},
{ timestamps: true, versionKey: false }
)
export default Mongoose.model('Items', schema)
Import Item model and save will convert string into mongoose objectId
const myNewItem = {
categoryId: "5fc0a6e58dc3892120595384",
title: "Apple"
}
const myNewItemSave = await Item.create(myNewItem);
#Ashok defines a type in the model, if you dont want to modify the model you can "convert" the id with mongoose.Types.ObjectId, eg:
const mongoose = require('mongoose')
const myNewItem = {
categoryId = mongoose.Types.ObjectId("5fc0a6e58dc3892120595384"),
title = "Apple"
}
I have Mongoose model:
const mongoose = require('mongoose')
const { Schema } = mongoose
const schema = new Schema({
Name: { type: String },
Category: { type: String },
Price: { type: Number }
})
module.exports = mongoose.model('Product', schema)
And I have to sort by Category field. Sort order is
['Clothes', 'Accessories', 'Footwears']
How cat I do it?
The MongoDB server doesn't offer any way to provide a custom sort function.
Javascript does, so you can get the results from the query as an array, and use a custom compare function with Array.sort
I solved it by adding weight of Category. Now my model is like this:
const schema = new Schema({
Name: { type: String },
Category: { type: String },
CategoryWeight: { type: Number },
Price: { type: Number }
})
And I sorting like this:
const products = await Product.find().sort('-CategoryWeight')
Here is my Game Schema :
var mongoose = require('mongoose');
const GameSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
publishers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Publisher'
}
]
});
var GameModel = mongoose.model('Game', GameSchema);
module.exports = GameModel;
Here is my Publisher Schema :
var mongoose = require('mongoose');
const PublisherSchema = new mongoose.Schema({
companyName: {
type: String,
required: true
},
firstParty: {
type: Boolean,
required: true
},
website: {
website: String,
}
});
var PublisherModel = mongoose.model('Publisher', PublisherSchema);
module.exports = PublisherModel;
I have a picture of what you can find in my collection "games" in mongoDB :
When I use this route :
router.get('/games', async function(req, res) {
const games = await Game
.find()
.populate('publishers')
.select('title publishers')
res.json(games);
})
I have empty arrays as result for the publishers. If I don't use an array in Schema, this is correcly populated and I got data of publisher into each game. So why mongoose doesn't populate when it is an array?
Check below by modifying the schema definition as below
I think the below could fix your issue, please give a try by redefining the publishers as below
Publishers: [
publisher: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Publisher'
}
]
I think the definition of schema is more about to define the structure of the object that we would like to process, rather about the number of objects that we want to process.
The Schema definition with what I know is defining the semantics of the model and to take advantage of the middle ware functionalities.
You can save multiple objects of which meet the same semantic definition but the definition itself cannot be an array
Thanks
Pavan
I have a Mongo query which returns the correct results in the Mongo console but when the same query is performed against a Mongoose model it returns an empty array.
It's the following line which isn't working as it should:
query.facilities = {$in: facilities.split(',')};
Declare my mongoose models
// places
placeSchema = mongoose.Schema({
name: String,
category: [{ type: Schema.Types.ObjectId, ref: 'categories' }],
facilities: [{ type: Schema.Types.ObjectId, ref: 'facilities' }],
});
Place = mongoose.model('places', placeSchema);
// categories
categorySchema = mongoose.Schema({
name: String,
slug: String
});
Category = mongoose.model('categories', categorySchema);
facilitiesSchema = mongoose.Schema({
name: String,
});
Facility = mongoose.model('facilities', facilitiesSchema);
My /places route
app.get('/places', function(req, res){
var geo = req.query.geo.split(',');
if(geo.length !== 2) {
handleError('valid_geo_coords_required');
}
var limit = typeof req.query.limit !== 'undefined' ? req.query.limit : 0;
var category = req.query.category;
var facilities = req.query.facilities;
var query = {
loc: {$near: geo}
};
if(typeof category !== 'undefined') {
query.category = category;
}
if(typeof facilities !== 'undefined') {
query.facilities = {$in: facilities.split(',')}; <---- this causes the problem
}
console.log(query); // pasting this into the mongo console returns correct results
Place.find(query).limit(limit).populate('category').populate('facilities').exec(function(err, data){
if (err) return handleError(err);
res.json(data);
});
});
The query object is:
{ loc: { '$near': [ '-3.188384', '55.94772' ] }, facilities: { '$in': [ '53012d6965b5e9a35efbb215' ] } }
This is the query I perform in the console:
db.places.find({ loc: { '$near': [ '-3.188384', '55.94772' ] }, facilities: { '$in': [ '53012d6965b5e9a35efbb215' ] } })
and returns a valid document.
Is there something specific to Mongoose which is affecting this?
Update
It seems to be this line that breaks it:
facilities: [{ type: Schema.Types.ObjectId, ref: 'facilities' }],
maybe because it's an array of objectId's?
If that query works in the Mongo shell, then the facilities array field of the docs in the places collection must contain strings and not ObjectIDs.
However, based on your schema definition for places, Mongoose will cast facilities values in your query to ObjectIDs which then don't match the docs in places because it contains strings.
The fix is to modify your facilities values in the docs of the places collection to be ObjectIDs instead of strings.