I have scheme with embedded discriminators, and I want to clone it. But when I've create model from this cloned schema, and try to create document, some properties, related to this discriminators are goes away.
Here the code
const mongoose = require('mongoose');
const propertiesSchema = new mongoose.Schema({
name: { type: String },
},
{ discriminatorKey: 'type', _id: false });
const collectionSchema = new mongoose.Schema({
name: { type: String },
properties: [propertiesSchema]
});
const propertiesArray = collectionSchema.path(`properties`);
propertiesArray.discriminator(`type1`,
new mongoose.Schema({ type1: String }, { _id: false })
);
propertiesArray.discriminator(`type2`,
new mongoose.Schema({ type2: String }, { _id: false })
);
const Collection = new mongoose.model('Collection', collectionSchema);
const Clone = new mongoose.model('Clone', Collection.schema.clone());
const data = {
name: "Collection",
properties: [
{ type: "type1", type1: "type1-1" },
{ type: "type2", type2: "type2-2" }
]
}
console.log(new Collection(data));
console.log(new Clone(data));
Result is:
{ _id: 5d1b583e6d2d8b519c8849b8,
name: 'Collection',
properties:
[ { type: 'type1', type1: 'type1-1' },
{ type: 'type2', type2: 'type2-2' } ] }
{ _id: 5d1b583e6d2d8b519c8849b9,
name: 'Collection',
properties: [ { type: 'type1' }, { type: 'type2' } ] }
So question is - why documents are different, and how to correctly clone, or "re-apply" discriminators on cloned scheme ?
node: v10.15.3
mongoose: 5.6.2
Issue will be fixed in version 5.6.4
Github fix commit
Related
This is my category schema where i have nested nestedCategorySchema and I want to refer to this ObjectId of this in other collection
`
const mongoose = require("mongoose");
const { Schema } = mongoose;
const nestedCategorySchema = new Schema({
name: {
type: Schema.Types.ObjectId,
},
});
const categorySchema = new Schema(
{
clientname: {
type: Schema.Types.String,
},
categoryOne: {
type: [nestedCategorySchema],
default: [],
},
categoryTwo: {
type: [nestedCategorySchema],
default: [],
},
},
{
timestamps: true,
}
);
exports.default = mongoose.model("category", categorySchema);
mongoose.model("category").collection.createIndex({
clientname: 1,
});
`
In another collection I want to refer the nested categoryOne ObjectId
`
const mongoose = require("mongoose");
const { Schema } = mongoose;
const prodSchema = new Schema(
{
categories: [
{
_id: false,
clientname: {
type: String,
},
** categoryLevelOne: {
type: mongoose.Schema.Types.ObjectId,
ref: "category.categoryOne",
},**
},
],
},
{
timestamps: true,
}
);
`
In prodSchema I want to refer to nested categoryOne
Try to declare the nestedCategorySchema as a model:
mongoose.model("nestedCategory", nestedCategorySchema);
And change the the categoryOne attribute in categorySchema to a ObjectId ref:
categoryOne: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'nestedCategory',
default: []
}];
Finally, given your configuration, you should probably change the categories property in prodSchema to a ref itself:
const prodSchema = new Schema(
{
categories: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'category'
},
],
},
{
timestamps: true,
}
);
In mongoose you can only create references to ObjectIds.
I have a problem while querying mongodb with nested multiple objects.
I am trying like this
Project.find()
.then((project) => {
RoadMap.find({
scheduledDate: {
$gte: new Date(req.params.gte), $lt: new
Date(req.params.lt)
}
})
.populate("roadMap", "_id title")
.populate("projectId", "_id title photo ")
.exec((err, roadmap) => {
if (err) {
return res.status(422).json({ error: err });
}
res.json({ project, roadmap });
});
})
.catch((err) => {
return res.status(404).json({ error: "project not found" });
});
I am getting results like this
{
project: {
}
roadmap: [{}{}]
}
but I want to achieve like this
{
project: {
_id:
title:
roadmap: [{},{}]
}
}
this is my schema:
projectShema:
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema.Types;
const projectSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
photo: {
type: String,
required: true,
},
caption: {
type: String,
},
postedBy: {
type: ObjectId,
ref: "User",
},
news: [
{
type: ObjectId,
ref: "News",
},
],
roadMap: [
{
type: ObjectId,
ref: "RoadMap",
},
],
},
{ timestamps: true }
);
mongoose.model("Project", projectSchema);
roadMapSchema:
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema.Types;
const roadmapSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
postedBy: {
type: ObjectId,
ref: "User",
},
projectId: { type: ObjectId, ref: "Project" },
categoryName: { type: String },
status: {
type: String,
default: "created",
},
},
{ timestamps: true }
);
mongoose.model("RoadMap", roadmapSchema);
I am not sure how to achieve the results, do I need to change schema or it is possible here also?
thank you
I have this document in mongo atlas
_id: 5f8939cbedf74e363c37dd86,
firstname: "Person",
lastname: "Person lastname",
sex: "Masculino",
age: "20",
birthDay: 2020-10-07T00:00:00.000+00:00,
vaccines: Array
0:Object
dose: Array
_id: 5f8939cbedf74e363c37dd87
vaccine:5f7023ad96f7ed21e85be521
createdAt:2020-10-16T06:12:27.726+00:00
updatedAt:2020-10-16T06:12:27.726+00:00
1:Object
dose:Array
_id:5f893a9ca98e97188c93fea8
vaccine:5f70259796f7ed21e85be523
2:Object
dose:Array
_id:5f893acda98e97188c93fea9
vaccine:5f7023ad96f7ed21e85be521
This is my mongoose schema
const mySchema = new Schema({
firstname: {
type: String,
required: true,
},
lastname: {
type: String,
required: true,
},
sex: {
type: String,
required: true,
},
age: {
type: String,
required: true,
},
birthDay: {
type: Date,
required: true,
},
vaccines: [
{
type: new Schema(
{
vaccine: {
type: Schema.ObjectId,
ref: "Vaccine",
},
dose: Array,
},
{ timestamps: true }
),
},
],
});
every time I add a new person the vaccines array gets one new object with the timestamp as you can see, in my js file I use this code:
const addPerson = (person) => {
const myPerson= new Model(person);
return myPerson.save();
};
Then when I add a new vaccine for the same person this does not get the timestamp, I'm using this code for that:
const addPersonVaccine = async ({ params, body }) => {
if (!params) return Promise.reject("Invalid ID");
const vaccines = [body];
const foundPerson = await Model.updateOne(
{
_id: params,
},
{
$push: {
vaccines: vaccines,
},
}
);
return foundPerson;
};
This is what my body inside vaccines array has:
[ { vaccine: '5f72c909594ee82d107bf870', dose: 'Primera' } ]
The problem is that I have no results about the next timestamps, as you can see in my mongo atlas document:
1:Object
dose:Array
_id:5f893a9ca98e97188c93fea8
vaccine:5f70259796f7ed21e85be523
2:Object
dose:Array
_id:5f893acda98e97188c93fea9
vaccine:5f7023ad96f7ed21e85be521
Is that the best way to implement timestamps in subdocuments or sub schemas?
I will appreciate your answers, thnks 👏
You can use mongoose schema timestamps options to the inner schemas
const mongoose = require("mongoose");
const forumSchema = new mongoose.Schema(
{
title: { type: String, required: true },
biddings: [
{
type: new mongoose.Schema(
{
biddingId: String,
biddingPoints: Number
},
{ timestamps: true }
)
}
]
},
{ timestamps: true }
);
const Forum = mongoose.model("Forum", forumSchema);
module.exports = Forum;
for more Mongoose schema set timestamp on nested document
I defined two schema in mongoose: DocSchema has DocTypeSchema reference.
const DocTypeSchema = new Schema({
name: { type: String, unique: true, index: true }
});
export const DocType = mongoose.model('Doc-Type', DocTypeSchema);
const DocSchema = new Schema(
{
name: { type: String },
type: { type: Schema.Types.ObjectId, ref: 'Doc-Type' },
description: { type: String },
}
);
When I try to get the docs with type by the name I gets empty results.
How can I solve this?
docs.find({ 'type.name': 'VideoBook' }, { limit: 30 })
I don't want to get the type object inside the docs array. just to gets the docs that match to the query.
You need tu user .aggregate
Specify the collection:
const DocTypeSchema = new Schema({
name: { type: String, unique: true, index: true }
},{ collection: 'docType' });
Simple example :
const docs = await Doc.aggregate([
{
$lookup: {
from: 'docType',
localField: 'type',
foreignField: 'name',
as: 'magic'
}
},
{$unwind: '$magic'},
{
$match: {
$and: {
"magic.name": 'VideoBook'
}
}
},
{ $limit : 30 }
])
I commented the line of code with // This Command Does not work where I suspect that it is breaking. In the debug log of mongoose, the output looks like this: But nothing is added to the medicineIds array in the Monday object for the DaysOfWeek schema.
The following is the debug output for DayOfWeek.findOneAndUpdate() where I push back onto the array, and am not seeing the result in my mongo database.
Mongoose: dayofweeks.insertOne({ medicineIds: [], _id: 'Monday', __v: 0 }, { session: null }) // <- response to $push
Mongoose: medicines.insertOne({ times: [ 1, 2 ], dayNames: [ 'Monday' ], _id: ObjectId("5e73d816d54b1202e15bb96b"), nam
e: 'Provolone', count: 23, __v: 0 }, { session: null })
Mongoose: dayofweeks.findOne({ _id: 'Monday' }, { projection: {} })
Mutation
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
addDayOfWeek: {
type: DayOfWeekType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) }
},
resolve(parent, args) {
let dayOfWeek = new DayOfWeek({
_id: args.name,
medicineIds: new Array()
});
return dayOfWeek.save();
}
},
addNewMedicine: {
type: MedicineType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) },
count: { type: new GraphQLNonNull(GraphQLInt) },
times: { type: new GraphQLNonNull(GraphQLList(GraphQLInt))},
dayNames: { type: new GraphQLNonNull(GraphQLList(GraphQLString))}
},
resolve (parent, args) {
let medicine = new Medicine({
name: args.name,
count: args.count,
times: args.times,
dayNames: args.dayNames
});
args.dayNames.forEach((dayId) => {
DayOfWeek.findOneAndUpdate( // This Command Does Not Work:
// medicine._id, dayId are correct at this point of the
//code
{ _id: dayId },
{ $push: { medicineIds: medicine._id }},
{ new: true, useFindAndModify: false }
);
});
return medicine.save();
}
}
}
});
DayOfWeek Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const dayOfWeekSchema = new Schema({
_id: String,
medicineIds: [String] // I am trying to push onto this array
});
module.exports = mongoose.model('DayOfWeek', dayOfWeekSchema);
Medicine Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const medicineSchema = new Schema({
id: String,
count: Number,
name: String,
times: [Number],
dayNames: [String]
});
module.exports = mongoose.model('Medicine', medicineSchema);
await Promise.all(args.dayNames.map(dayName => {
return DayOfWeek.findOneAndUpdate({ _id: dayName }, { $push: { medicineIds: medicine._id }});
})).catch((err) => console.error(err));
return await medicine.save();
I just did that and it works. hmm.