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"
}
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
});
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
I have 2 collections for product and product price. In product collection there is a field named product_id which is in String and the same field is in productprice collection with the same name as String.
How can I decide Schema for this and how to populate for which product comes with a field as productprice with it?
product fields : _id,Product_id,name
Product price fields :
_id,Product_id,price
where the same value is in Product_id for both the collections.
const productpriceSchema = mongoose.Schema({
Product_id: {
type: mongoose.Schema.ObjectID,
ref: 'Product'
},
price: String
});
const productSchema = mongoose.Schema({
Product_Name: type: String,
User_Object_ID :type: String,
cid :type: String
});
const Product = module.exports = mongoose.model('Product', productSchema);
const Productprice = module.exports = mongoose.model('Product_price', productpriceSchema);
module.exports.productwithprice = function(callback,limit){
Productprice.find({}, callback).populate('Product_id')
}
//Product Schema
//you don't have to give field _id, mongodb will automatically generate it.
const productSchema = new Schema({
Product_Id: String,
name: String
});
const Product = mongoose.model('Product', productSchema);
//Product Price Schema
const productPriceSchema = new Schema({
Product_Id: {
type: Schema.ObjectId,
ref: 'Product'
},
price: String
});
const ProductPrice = mongoose.model('ProductPrice', productPriceSchema)
ProductPrice.find({query})
.populate('Product_Id')
.exec((err, products) => {
//Logic
});
var ProductSchema = new Schema({
name: String,
productId: String
});
var PriceSchema = new Schema({
name: String,
productId: String
});
ProductSchema.virtual('price', {
ref: 'Price', // The model to use
localField: 'productId', // Find price where `localField`
foreignField: 'productId', // is equal to `foreignField`
// If `justOne` is true, 'price' will be a single doc as opposed to
// an array. `justOne` is false by default.
justOne: true
});
var Product = mongoose.model('Product ', ProductSchema);
var Price = mongoose.model('Price ', PriceSchema);
Product.find({}).populate('price').exec(function(error, products) {
/* `products.price` is available now */
});
For detail, please check Populate Virtuals section of Mongoose population.
I'm trying to make a very simple thing : Populate hasMany documents (links) from an document (product)
According to Mongoose documentation about population
My Product model is like :
const modelSchema = schema({ // const schema = mongoose.Schema
[...]
_links: [{
type: schema.Types.ObjectId,
ref: 'Link'
}]
})
const Product = mongoose.model('Product', modelSchema)
and my Link model :
const modelSchema = schema({
[...]
_product: {
type: schema.Types.ObjectId,
ref: 'Product'
}
})
const Link = mongoose.model('Link', modelSchema)
I can save in both sides, find any record, populate product from Link.find().populate('_product')
but, impossible to populate links from a product :
Product
.find()
.populate('_links')
.exec(...)
-> {
_links: []
}
What I'm doing wrong ?
I've also notice that in the documentation, _id are forced to be Number, is it a part of the solution ?
If you have subdocument arrays, Mongoose automatically creates ids for each one. Example:
{
_id: "mainId"
subDocArray: [
{
_id: "unwantedId",
field: "value"
},
{
_id: "unwantedId",
field: "value"
}
]
}
Is there a way to tell Mongoose to not create ids for objects within an array?
It's simple, you can define this in the subschema :
var mongoose = require("mongoose");
var subSchema = mongoose.Schema({
// your subschema content
}, { _id : false });
var schema = mongoose.Schema({
// schema content
subSchemaCollection : [subSchema]
});
var model = mongoose.model('tablename', schema);
You can create sub-documents without schema and avoid _id. Just add _id: false to your subdocument declaration.
var schema = new mongoose.Schema({
field1: {
type: String
},
subdocArray: [{
_id: false,
field: { type: String }
}]
});
This will prevent the creation of an _id field in your subdoc.
Tested in Mongoose v5.9.10
Additionally, if you use an object literal syntax for specifying a sub-schema, you may also just add _id: false to supress it.
{
sub: {
property1: String,
property2: String,
_id: false
}
}
I'm using mongoose 4.6.3 and all I had to do was add _id: false in the schema, no need to make a subschema.
{
_id: ObjectId
subDocArray: [
{
_id: false,
field: "String"
}
]
}
You can use either of the one
var subSchema = mongoose.Schema({
//subschema fields
},{ _id : false });
or
var subSchema = mongoose.Schema({
//subschema content
_id : false
});
Check your mongoose version before using the second option
If you want to use a predefined schema (with _id) as subdocument (without _id), you can do as follow in theory :
const sourceSchema = mongoose.Schema({
key : value
})
const subSourceSchema = sourceSchema.clone().set('_id',false);
But that didn't work for me. So I added that :
delete subSourceSchema.paths._id;
Now I can include subSourceSchema in my parent document without _id.
I'm not sure this is the clean way to do it, but it work.
NestJS example for anyone looking for a solution with decorators
#Schema({_id: false})
export class MySubDocument {
#Prop()
id: string;
}
Below is some additional information from the Mongoose Schema Type definitions for id and _id:
/**
* Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field
* cast to a string, or in the case of ObjectIds, its hexString.
*/
id?: boolean;
/**
* Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema
* constructor. The type assigned is an ObjectId to coincide with MongoDB's default behavior. If you
* don't want an _id added to your schema at all, you may disable it using this option.
*/
_id?: boolean;