I've got a question about discriminators and mongoose/mongodb. I would like to understand how I can update one document which contains 2 properties whichs are array of discriminators.
Here my mongoose models :
const mongoose = require('mongoose');
const carSchema = require('./car');
const continentalWheelSchema = require('./wheel/continental');
const michelinWheelSchema = require('./wheel/michelin');
const CarSchema = new mongoose.Schema({}, { discriminatorKey: 'type', _id: false } );
const WheelSchema = new mongoose.Schema({}, { discriminatorKey: 'type', _id: false } );
const ClientParkSchema = new mongoose.Schema({
customer: { type: String, required: true },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
cars: [CarSchema],
wheels: [WheelSchema]
});
ClientParkSchema.path('cars').discriminator('break', carSchema);
ClientParkSchema.path('wheels').discriminator('continental', continentalWheelSchema);
ClientParkSchema.path('wheels').discriminator('michelin', michelinWheelSchema);
module.exports = {
ClientPark: mongoose.model('client_park', ClientParkSchema, 'client_park')
};
/////////////////////// CAR SCHEMA ////////////////////////
const mongoose = require('mongoose');
const CarSchema = new mongoose.Schema({
brand: { type: String, required: true },
model: { type: String, required: true },
}, { _id: false } );
module.exports = CarSchema;
/////////////////////// CONTINENTAL WHEEL SCHEMA ////////////////////////
const mongoose = require('mongoose');
const ContinentalWheelSchema = new mongoose.Schema({
model: { type: String, required: true }
}, { _id: false } );
module.exports = ContinentalWheelSchema;
/////////////////////// MICHELIN WHEEL SCHEMA ////////////////////////
const mongoose = require('mongoose');
const MichelinWheelSchema = new mongoose.Schema({
price: { type: number, required: true},
model: { type: String, required: true },
season: { type: String, required: true }
}, { _id: false } );
module.exports = MichelinWheelSchema;
mongodb query :
db.client_park.updateOne({_id: ObjectId('5d3865a4e56473518adabd35'), "car.type": 'break',"wheel.type": "michelin"}, {$set: {"car.$.brand": 'Ford',"wheel.$.price": 100,"wheel.$.season": "summer"}})
The query seems to work but the document is not updated. So I would like to know how could I update my document by discriminators (if there are exists).
Thank you very much !
EDIT :
The document I want to update :
{
"_id":"5d39a19e2376c7089ec7707b",
"customer":"5d0757aa4b6620003335aff2",
"cars":[
{
"type":"break",
"brand":"Ford"
}
],
"created_at":"2019-07-25T12:33:34.799Z",
"updated_at":"2019-07-25T12:33:34.799Z",
"_v":0
}
Related
I'm trying to find out the way to remove nested object in one collection once the document from another collection is expired
LocationsSchema.js
const mongoose = require('mongoose');
const locationsSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Please add a location name (string)']
},
confirmedBookings: [
{
startDate: {
type: Number
},
finishDate: {
type: Number
}
}]
}, {
timestamps: true
})
module.exports = mongoose.model('Locations', locationsSchema)
BookingsSchema.js
const mongoose = require('mongoose');
const Location = require('./locationModel');
const bookingSchema = mongoose.Schema({
startDate: {
type: Number,
required: [true, 'Please add a valid Date']
},
finishDate: {
type: Number,
> timestamp
required: [true, 'Please add a valid Date'],
index: true
},
location: {
type: mongoose.Schema.Types.ObjectId,
ref: Location
}
}, {
timestamps: true
})
bookingSchema.index({finishDate: 1}, {expireAfterSeconds: 0})
module.exports = mongoose.model('Booking', bookingSchema)
This is how I delete the object manually in
BookingsController.js
const deleteBookings = asyncHandler(async (req, res) => {
const booking = await Booking.findById(req.params.id);
if (!booking) {
res.status(400);
throw new Error('Booking not found');
}
await Location.findOneAndUpdate({_id: booking.location},
{$pull: {'confirmedBookings': {_id: req.params.id}}});
await booking.remove();
res.status(200).json({id: req.params.id});
})
But I also want to be able to delete the objects ones theirs finishDate are before the present time.
I tried to create an TTL index for that but it seems it doesn't work in the way I did it
I have mongoose Schema , where i have schemas by language. I want to loop them depend my other language model. Now I have them static(en, ru, ge).
const StrategyTranslatedFieldsSchema = mongoose.Schema(
{
title: String,
teaser: String
},
{ _id : false }
)
const StrategySchema = mongoose.Schema({
en: StrategyTranslatedFieldsSchema,
ge: StrategyTranslatedFieldsSchema,
ru: StrategyTranslatedFieldsSchema,
},
{
timestamps: true
});
my language schema:
const languageSchema = mongoose.Schema({
en:{
type: String,
default: 'en'
},
ru:{
type: String,
default: 'ru'
},
ge:{
type: String,
default: 'ge'
},
})
want something like that:
const mongoose = require('mongoose');
const slug = require('mongoose-slug-updater');
const Language = require('../models/Language')
mongoose.plugin(slug);
const StrategyTranslatedFieldsSchema = mongoose.Schema(
{
title: String,
teaser: String
},
{ _id : false }
)
const StrategySchema = mongoose.Schema({
slug: {
type: String,
slug: "en.title",
slugPaddingSize: 2,
unique: true
},
status:{
type: Boolean,
default: true
},
for(let key in Language){
key: StrategyTranslatedFieldsSchema
}
},
{
timestamps: true
});
const Strategy = mongoose.model('strategy', StrategySchema);
module.exports = Strategy;
Also interesting is it good practice to save multilingual data, like that example?
Thanks
You can do something like this.
// create object you want to pass StrategySchema
const strategySchemaObject = {
slug: {
type: String,
slug: "en.title",
slugPaddingSize: 2,
unique: true
},
status:{
type: Boolean,
default: true
}
}
// add each field to your schema object
Object.keys(Language.schema.obj).forEach((lang) => {
strategySchemaObject[lang] = StrategyTranslatedFieldsSchema
})
// create your schema
const StrategySchema = mongoose.Schema(strategySchemaObject, {
timestamps: true
})
I have a model like this
const Schema = mongoose.Schema
const fileSchema = mongoose.Schema({
ownerId: { type: Schema.Types.ObjectId },
fileTypeId: { type: Schema.Types.ObjectId },
name: { type: String },
data: { type: Schema.Types.Mixed },
fileSize: { type: Number },
isHashInBlockchain: { type: Boolean },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
})
fileSchema.virtual('file', {
ref: 'filetype',
localField: 'fileTypeId',
foreignField: '_id'
})
fileSchema.set('toObject', { virtuals: true })
fileSchema.set('toJSON', { virtuals: true })
module.exports = mongoose.model('useruploadedfiles', fileSchema)
I am referring filetype collection to this model
But when I run the following query
await File.find(query).populate({ path: 'file' }).select('_id name createdAt updatedAt').sort({ createdAt: -1 }).skip(limit * (pageNumber - 1)).limit(limit)
I am getting the following error
Schema hasn't been registered for model "filetype"
You have to import your model in your root app file.
model.js
const UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
trim: true,
},
name: {
type: String,
required: "Please supply a name",
trim: true
},
});
module.exports = mongoose.model("User", UserSchema);
app.js
mongoose.connect(process.env.DATABASE);
mongoose.Promise = global.Promise; // Tell Mongoose to use ES6 promises
mongoose.connection.on('error', (err) => {
console.error(`🙅 🚫 🙅 🚫 🙅 🚫 🙅 🚫 → ${err.message}`);
});
// READY?! Let's go!
require('./models/User')
router.js
const User = mongoose.model("User");
const getUsers = async (req, res) => res.json(await User.find({}));
app.get('/users', getUsers);
I'm trying to remove a product from a category using mongoose .remove from these other questions but none seem to work
Remove sub-document from Mongo with mongoose
But nothing is happening and I only get back the same thing unedited
Category Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Product = require('./Product');
const CategorySchema = Schema({
_id: Schema.Types.ObjectId,
categoryName: {
type: String,
required: true,
},
categoryDescription: String,
productList: [Product],
});
mongoose.model('Category', CategorySchema);
Products Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ProductSchema = Schema({
productName: {
type: String,
required: true,
},
productDescription: String,
categories: { type: Schema.Types.ObjectId, ref: 'Category' },
});
mongoose.model('Product', ProductSchema);
My express route to handle deleting of the subdocument
app.delete('/api/category-with-product/:categoryId', (req, res) => {
const categoryId = req.params.categoryId;
const { productId } = req.body;
Category.findById(categoryId)
.then((category) => {
category.productList.pull({ _id: productId });
return category.save();
})
.then((newCategory) => {
res.send(newCategory);
});
});
My expected outcome is for this is to just remove the product in the productList array
{
_id: 5c5b990d56b3f61ce3736e6f,
categoryName: 'A new category name',
description: 'description',
productList:[
{ _id: 5c6e4b5114333b25f8e9d737,
productName: 'test',
productDescription: 'test'
}
],
}
Could you please try this:
const ObjectId = mongoose.Types.ObjectId;
function funcName() {
return new Promise((resolve, reject) => {
db.category.update(
{ },
{ $pull: { productList: { _id: ObjectId(productId) } } },
{ multi: true }
)
.then((result) => resolve())
.catch((err) => reject(err));
});
}
You can also try Async/Await during database operations.
I have a document which can have an array of different sub documents.
Saving documents to the database work fine and the structure is exactly what I need.
My Problem is that I can not update values in the "sections" array (schema below)
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const logoSchema = require('./site-sections/logo');
var sectionSchema = new Schema(
{
show: { type: Boolean, default: true },
order: Number
},
{ discriminatorKey: 'type' }
);
const siteSchema = new Schema({
_user: { type: Schema.Types.ObjectId, ref: 'User' },
type: { type: String, required: true },
title: { type: String, default: '' },
name: { type: String, required: true },
password: { type: String, default: '' },
caching: { type: Number, default: 1 },
unique_id: { type: String, required: true },
sections: [sectionSchema]
});
const sectionArray = siteSchema.path('sections');
const headerSchema = new Schema({
image: { type: String, default: '' },
title: { type: String, default: '' },
sub_title: { type: String, default: '' },
show: { type: Boolean, default: true },
logo: logoSchema
});
sectionArray.discriminator('header', headerSchema);
const textSchema = new Schema({
text: String
});
sectionArray.discriminator('text', textSchema);
module.exports = mongoose.model('site', siteSchema);
My Update function:
req.body has the following value:
{ key: 'title',
value: 'Test',
unique_site_id: '_jxn7vw' }
const Site = require('../../models/site');
exports.update = async function(req, res, next) {
console.log(req.body);
if (req.body.unique_site_id) {
Site.update(
{
unique_id: req.body.unique_site_id,
_user: req.user.id,
'sections.type': 'header'
},
{
$set: {
['sections.$.' + req.body.key]: req.body.value
}
},
function(err, status) {
if (err) {
console.log(err);
return res.status(500).send();
}
console.log(status);
return res.status(200).send();
}
);
}
};
The console.log(status) always prints: { ok: 0, n: 0, nModified: 0 }.
How can I update the title value?
Discriminator keys cannot be updated. https://github.com/Automattic/mongoose/issues/3839
Ok. So the right order is:
convert mongoose document to object with toObject()
change discriminator, and change/delete other properties
convert back to mongoose document with hydrate()
save