mongodb doesnt save 2 objects inside the main object - mongodb

I want to save an object that has and object and array inside it. But when I end up saving the data in the mongo, it doesnt save a few properties.
like "entityMap": {}, data: {}
body =
{ entityMap: {},
blocks:
[ { key: '637gr',
text: 'Books selected for the you ',
type: 'header-four',
depth: 0,
inlineStyleRanges: [Array],
entityRanges: [],
data: {} } ] }
Heres how my mongo schema structured.
const mongoose = require('mongoose');
const { Schema } = mongoose;
const bookSchema = new Schema({
body: {
type: {},
required: false
},
templateName: {
type: String,
required: true
},
subject: {
type: String,
required: true
},
googleId: {
type: String,
required:true
},
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
mongoose.model('books', bookSchema);

When declaring the property with type {}, mongoose uses the Schema.Types.Mixed type. This way the property may contain anything, but mongoose won't detect changes made to it. You have to manually tell mongoose that the property was modified:
book.body = { foo: { bar: { quux: 'foo' } } }
book.markModified('body');
book.save()
Mongoose SchemaTypes

Related

Recursive mongoose schema does not result in correct object stores

I have a recursive model schema defined in a schema which uses the add() method in the Schema class to incrementally build the schema. It seems to build the paths correctly as shown when I print out the paths. However, when I use the Model defined to store the object in the database, it is missing the inner BNode. Here is a definition of the schema:
import mongoose from 'mongoose';
const BNodeSchema = new mongoose.Schema({
bValue: { type: [Number] },
id: String,
})
const RValue = {
rId: String,
value: Number
}
const ANodeSchema = new mongoose.Schema({
type: {
id: String,
rValues: {
type: Map,
of: RValue
},
}
})
const QuestSchema = new mongoose.Schema({
type: {
_id: { type: String, },
aNode: ANodeSchema,
bNodes: [BNodeSchema],
url: {
type: String
},
id: {
type: String
}
},
},
{ id: false }
)
ANodeSchema.add({ quest: QuestSchema });
const QuestNodeSchema = new mongoose.Schema({
_id: { type: String, unique: true },
quests: { type: [QuestSchema] },
}, {
id: false
})
export const QuestModel = mongoose.model('QuestModel', QuestNodeSchema);
QuestNodeSchema.eachPath(function(path:any) {
console.log(path);
});
{
_id: 12223,
quests:[
{
id: 'Quest-111-111' ,
aNode: {
id: 'A222222',
rValues: {
rId: 'RR1222',
value: 44422
},
quest:{
url: 'https://deptio-opcom',
id: '22222-QST',
bNodes:[{
bValue: 'B22190',
value: 22085
}]
}
}
}
]
}
I have included a sample of the json I am storing in the database. I use a class, not included for brevity to create the equivalent JSON object in the final format to be stored. My feeling is that there is something not quite right with my schema definition. I would be most grateful if someone could help me figure out what I am missing in my definition. Thanks a lot

How to loop items in mongoose schema

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
})

Create ref to sub document's array for each property of subdocument

Model A looks like
{ a : {
step1: [{
type: { type: String },
category: { type: String },
}],
step2: [{
type: { type: String },
category: { type: String },
}]
} }
Model B which I wanted to create should contain a prop which will ref to Model A.step1 or A.step2 , trying to acheive this by following
{ progress : [
{
step: {
type: Schema.Types.ObjectId,
ref: "A.a.{What should be here}",
required: true,
},
details: { type: Schema.Types.Mixed },
}
]
}
I think you need to create Schemas for all of them :)
I would just separate the three completely - not sure if this is viable to you as the whole idea behind this is a bit mysterious, but would something like this work for you?
const stepSchema = new Schema({
type: String,
category: String,
});
const Step = mongoose.model("steps", stepSchema);
const aSchema = new Schema({
step1: [stepSchema],
step2: [stepSchema],
});
const A = mongoose.model("as", aSchema);
const progressSchema = new Schema({
a: { type: aSchema, required: true, ref: "as"},
progress: [{ type: stepSchema, required: true, ref: "steps" }],
details: Schema.Types.Mixed,
});
const Progress = mongoose.model("progresses", aSchema);

Mongoose, proper way to update documents with deep nested schemas

I would like to know what would be the most efficient way to update a document that also has a nested schema in it. Normally I would just use Model.findByIdAndUpdate(id, updatedValues) ..., however if I try to do that with a document that has a deep nested schema I get this error: CastError: Cast to Embedded failed for value "{ _id: 5b1936aab50e727c83687797, en_US: 'Meat', lt_LT: 'Mesa' }" at path "title".
My Schemas look something like:
const titleSchema = new Schema({
en_US: {
type: String,
required: true
},
lt_LT: {
type: String,
default: null
}
})
const categorySchema = new Schema({
title: titleSchema
});
const ingredientSchema = new Schema({
title: {
type: titleSchema,
required: true
},
category: categorySchema,
calories: {
type: Number,
min: 0,
default: 0
},
vitamins: [String]
})
And I try to update like so:
{
title: {
en_US: 'Pork',
lt_LT: 'Kiauliena'
},
category: {
_id: '5b193a230af63a7e80b6acd8',
title: {
_id: '5b193a230af63a7e80b6acd7'
en_US: 'Meat',
lt_LT: 'Mesa'
}
}
}
Note, I get the new category object from a separate collection using just the category _id, but the final update object that goes into the findByIdAndUpdate() function looks like the one above.
The only workout I found is to remove the category from the updated values, update the document via findByIdAndUpdate(), get the updated document, assign the new category to it and save it.
It works just fine and all, but that requires two calls to the database, is it possible to do it in just one?
Try updating your schema like this:
const titleSchema = new Schema({
en_US: {
type: String,
required: true
},
lt_LT: {
type: String,
default: null
}
});
const ingredientSchema = new Schema({
title: {
type: titleSchema,
required: true
},
category: {
title: titleSchema
},
calories: {
type: Number,
min: 0,
default: 0
},
vitamins: [String]
});

MongoDB - Update Array with different types (discriminatorKey)

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