Mongoose did not sent the data as expected - node.js

I had a mongoose object at server side:
...
item = {
name: "Test",
id: 1
}
// item's an mongo schema
// id and name defined in model as String and Number
Then I add into item new field mentions:
item.mention = [{ id: 1, ... }]
But I can't get mention at client side.
My response code:
res,json({ status: 1, message: 'success', data: item })
The response was data: { name: "Test", id: 1 }
I don't want to add mention into my mongo schema.
So, what's my problem?
How can I fix that?
Thanks!

The problem is that mongoose will not allow you to modify item document if a field you are trying to set value for does not exists in schema of the model, which is your case is "mention" field.
If you want to add "mention" field you have to access _doc field of the item document. Example :-
item._doc.mention = [{ id: 1, ... }]
Response should be:-
{ name: "Test", id: 1, mention: [{ id: 1, ... }] }

It is not usually recommended, but if you want to change schema like this.
you should pass strict false parameter to mongoose model while setting schema like this.
var ModelSchema = new Schema({
number: String,
}, { strict: false });
Now, it will change schema if you give any other parameter which is not in schema, it will add that one.

Related

Using same column with different valus in mongodb

Hi I tried to use the same column name more than once in mongoose but it showing different output.Instead of that I need the expected output is there any way to achieve it.Can anyone help me
const mongoose = require('mongoose')
mongoose.connect('----------------------------------------------',
{useNewUrlParser:true,useCreateIndex:true,useUnifiedTopology:true})
const wavicle = mongoose.model('Datasetlist',{
Dataset:[{
id:Number,
dataset:String,
parameter: [{
Name:String,
Name:String,
Name:String,
Name:String,
Name:String,
Name:String
}]
}]
})
const me = new wavicle({
Dataset:[{
id:1,
dataset:'Daily Food Report',
parameter: [{
Name:'StoreName',
Name:'Dates',
Name:'TransDesc',
Name:'Amount',
Name:'credit'
}]
}]
})
me.save().then(()=>{
console.log(me)
}).catch(()=>{
console.log(error)
})
OUTPUT:
_id:5f044c0165a79639745ce2a1
Dataset:Array
0:Object
_id:5f044c0165a79639745ce2a2
id:1
dataset:"Daily Food Report"
parameter:Array
0:Object
_id:5f044c0165a79639745ce2a3
Name:"credit"
__v:0
But I need the output as
EXPECTED OUTPUT:
dataset:[
{id:1,dataset:'Daily Food Report',parameter: [
{name:'Store Name'},
{name:'Dates'},
{name:'TransDesc'},
{name:'Amount'},
{name:'credit'},
{name:'Total'}
]
There are 3 issues here:
The schema definition: Although it actually works the way you define multiple keys with the same name, but at the end the keys will overwrite each others and you end up with an object of only one key. The way to do is as follows:
{
Dataset:[{
id:Number,
dataset:String,
parameter: [{
Name: String // be carful with the case, your expect the output to have the key "name", but you defined as "Name", the keys are case sensitive
}]
}]
}
Document creation: as mentioned in the first issue. If you define multiple keys with the same name, they will overwrite each others, then you probably end up with a single object in an array like this: parameters: [{ Name:'credit' }]. The correct way is to write separate objects
const me = new wavicle({
Dataset:[{
id:1,
dataset:'Daily Food Report',
parameter: [{
Name:'StoreName'
},{
Name:'Dates'
},{
Name:'TransDesc'
},{
Name:'Amount'
},{
Name:'credit'
}]
}]
})
The logging: when you do console.log(me). It's possible that it won't print all nested structures, So all you see is Array while there are nested objects inside. You should do the following instead
console.dir(me, { depth: null })

Why is an array in my mongoose model preventing me from querying

I have the following mongoose model
CartSchema = new Schema({
company: String,
items: [{
_id: Schema.ObjectId,
price: Number,
gears: [String]
}],
});
I access it via this simpe query
const response = await Cart.findOne( { "items": { _id: "5e4d7a5bcff77131f46d8aa9" } });
And this is my data in the mongo database
So from this information we can see that the only information that I have in my database that corresponds to the model is the items[0]._id which should be found with the query above. The odd thing is it returns null as long as this line gears: [String], is in my model. It is not required (I also tried setting it manually to required : false but I can't seem to get my data if this line is in my model. If I remove the line from my model, I can get the data just fine.
Am I missing something obvious here that would prevent me from getting my data because of the gears: [String] line in my model?
by this way, { "items": { _id: "5e4d7a5bcff77131f46d8aa9" } }, you're searching for an exact match, the items should be an object contains only the specified _id
instead, you should use the dot notation to filter by the _id in the items array
const response = await Cart.findOne( { "items._id": "5e4d7a5bcff77131f46d8aa9" });
hope it helps

Convert Sequelize model to JSON Schema for user input validation

Planning to use AJV
for validating user inputs. AJV needs data model JSON Schema to validate user inputs. So, we need to derive JSON Schema from Sequelize model. Is there a way to get JSON schema from Sequelize model programatically?
A late answer, but I ended up creating sequelize-to-json-schema to solve this for our needs.
It offers more customisation in terms of which attributes you include in your schema and adding virtual attributes that might be used by your create method or similar.
Example
// assuming you have a user model with the properties
// name (string) and status (enum: real, imagined)
const schemaFactory = require('sequelize-to-json-schema');
const factory = new SchemaFactory({
customSchema: {
user: {
name: { description: "The user's name" },
status: { description: 'Was it all just a dream?' },
},
}
hrefBase: 'http://schema.example',
});
const schemaGenerator = factory.getSchemaGenerator(User);
const schema = schemaGenerator.getSchema();
// Results in
schema = {
{
title: 'User',
'$id': 'http://schema.example/user.json',
type: 'object',
'$schema': 'http://json-schema.org/draft-06/schema#',
properties: {
name: {
'$id': '/properties/fullname',
type: 'string',
examples: [],
title: 'Name',
description: "The user's name",
},
status: {
'$id': '/properties/status',
type: 'string',
examples: ['REAL', 'IMAGINED'],
enum: ['REAL', 'IMAGINED'],
title: 'Status',
description: 'Was it all just a dream?'
}
}
}
}
Note: sequelize-to-json-schema generates draft-06 schemas, to use that with AJV, their README says you'll need to do:
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'));

Mongoose how to auto add _id to objects in array within collection item?

i have a mongo collection that looks like this:
{
name: string
_id: (auto set)
items: array[
name: string
url: string
items: array[
{
name: string,
url: string,
items: []
}
]
]
}
I'm using findByIdAndUpdate (with mongoose) to add an item into the items array:
Menu.findByIdAndUpdate(
req.body.parentid,
{
$push: {
items: {
name: req.body.item.name,
url: req.body.item.url,
items: []
}
}
},
{
safe: true,
upsert: true,
new: true
},
function(err, model) {
if (err !== null) {
console.log(err);
}
}
);
This works fine, but it does not add an _id to each object inserted into the items array. And i really need an id for each one.
I'm guessing it comes from the method used, findByIdAndUpdate as it looks more like an update rather than an insert. If my thinking is correct.
Using mongodb 3.2.10 and mongoose 4.7.6.
Any help would be really appreciated.
Thanks.
EDIT: the _id: (auto set) is not real, it's being automatically added via mongo. But just at the top level objects.
Found the solution in this thread: mongoDB : Creating An ObjectId For Each New Child Added To The Array Field
basically, added
var ObjectID = require('mongodb').ObjectID;
and then forcing the creation:
$push: {
items: {
_id: new ObjectID(),
name: req.body.item.name,
url: req.body.item.url,
items: []
}
}
You dont need to sepcify _id: (auto set) in mongoose schema it will automatically add unique _id with each document.
if you don't define _id in Schema, mongoose automatically add a _id to array item.
for example:
const countrySchema = new Schema({
name: {
type: String
},
cities: [
{
// don't define _id here.
name: String
}
],
});
now when you insert a row, the result is something like this:
{name : 'Iran', cities : [{_id : 6202902b45f0d858ac141537,name :
'Tabriz'}]}

How to insert data into subdocument using $push in query, instead of retrieving doc and saving it back

Edit: this was actually working
As the Mongoose - Subdocs: "Adding subdocs" documentation says, we can add a subdoc using the push method (i.e. parent.children.push({ name: 'Liesl' });)
But I want to go further, and would like to use the $push operator to insert subdocuments.
I have two Schemas: the ThingSchema:
var ThingSchema = mongoose.Schema({
name: {
type: String,
required: true
},
description: {
type: String
}
});
and the BoxSchema, the main document that has an array of subdocuments (things) of ThingSchema:
var BoxSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
description: {
type: String
},
things: {
type: [ThingSchema]
}
});
var BoxModel = mongoose.model('Box', BoxSchema);
I need every subdocument in things to have unique names - that is, that it would be impossible to insert a new document into this array that has a name value that already exists in the subdocs.
I'm trying to do something like:
var thingObj = ... // the 'thing' object to be inserted
BoxModel.update({
_id: some_box_id, // a valid 'box' ObjectId
"things.name": { "$ne": thingObj.name }
},
{
$push: { things: thingObj}
},
function(err) {
if (err) // handle err
...
});
but not getting any desired results.
What would be the correct way to add a ThingSchema subdocument into BoxSchema's thing array using the $push operator to do so in the query (must not add the subdoc if there's another subdoc named the same), instead of the Mongoose Docs way?
Edit: this is actually the issue
I made a mistake, the code above works as expected but now the problem I have is that when thingObj does not match the ThingSchema, an empty object is inserted into the things array:
// now thingObj is trash
var thingObj = { some: "trash", more: "trash" };
When executing the query given the above trash object, the following empty object is inserted into the subdocs array:
{ _id: ObjectId("an_obj_id") }
What I want this case, when the thingObj doesn't match the ThingSchema, is nothing to be added.
$addToSet adds something unique to the array (as in it checks for duplicates). But it only works for primitives.
What you should do is put things into their own collection and make a unique index on name. Then, make this change
things: {
type: [{type: ObjectId, ref: 'thingscollection'}]
}
this way you can do
BoxModel.update({
_id: some_box_id, // a valid 'box' ObjectId
"things": { "$ne": thingObj._id }
},
{
$addToSet: { things: thingObj._id}
},
function(err) {
if (err) // handle err
...
});
And when you fetch use .populate on things to get the full documents in there.
It's not exactly how you want it, but that's a design that might achieve what you're aiming for.

Resources