Check if Obejct is Empty: Mongoose Nested/Embedded Document - node.js

In my documents pre save hook, I check if all the properties from the nested property accident exist and have correct values. If accident does not exist at all this is also fine.
When I'm trying to save a doc which has no value on the nested property accident of my doc it still goes into my custom validation rules. This is because I fail to detect if this nested object is empty.
Property in the Schema
prescriptionSchema = mongoose.Schema({
accident: {
kind: String, #accident, workAccident,
date: Date,
company: String
},
...
Pre Save Hook
console.log _.isEqual(data.accident, {}) #false
console.log JSON.stringify data.accident #{}
console.log JSON.stringify data.accident == JSON.stringify {} #false
console.log JSON.stringify {} #{}
console.log Object.keys(data.accident).length #14
for key, value of data.accident
console.log key, value #gives me basically the whole document with functions etc.
Current Detection (not good code)
if data.accident? && (data.accident['kind'] || data.accident['date'] || data.accident['company']) #=> do validation
Seed
newRecipe = new RecipeModel()
for key, value of recipe
newRecipe[key] = value
newRecipe.save((err, result) ->
return next err if err?
return next "No Id" if !result._id?
return next null, result._id
)
I tried {}, null and nothing as values for recipe.accident.
Mongoose Version: 4.0.2
Node Version: 5.9

This solution worked although I now have _ids on the embedded objects which I don't need.
I moved out the object from the main schema and defined it as a own sub schema:
drugSchema = mongoose.Schema({
name: String,
exchangeable: Boolean
})
accidentSchema = mongoose.Schema({
kind: String, #accident, workAccident,
date: Date,
company: String
})
prescriptionSchema = mongoose.Schema({
drugs: [drugSchema],
dutiable: Boolean,
accident: accidentSchema,
...
After this, the object is undefined in the pre save hook.

By default, mongoose won't save empty objects. You need to disable the minimize option in your Schema.
prescriptionSchema = mongoose.Schema({
accident: {
kind: String, #accident, workAccident,
date: Date,
company: String
},
...
}, {
minimize: false
})
Source : http://mongoosejs.com/docs/guide.html#minimize
UPDATE : If it is not saving the object, you can try to use the markModified() method (http://mongoosejs.com/docs/schematypes.html#mixed).
And for your checking problem, you can perform a function which will check your fields. Here's two examples : https://jsfiddle.net/ew2um2dh/13/

Related

Node Js and Moongoose: How to loop into array of objects and delete a particular object and then update the whole document

My document schema is as follows:
const CollectionSchema = mongoose.Schema({
ImageCategory:{type:String,required:true},
imgDetails: [
{
_id: false,
imageUrl:{type:String},
imageName:{type:String},
imageMimeType:{type:String},
}
],
Date: {
type: String,
default: `${year}-${month}-${day}`,
},
},{timestamps: true,})
So in the database for example one document has multiple images with a single image category. What I am trying to do is I want to delete an object from imgDetails array.
Let me explain my question more precisely: imgDetails is an array
Explanation: I want to loop in imgDetails and then find (where imgageUrl === req.body.imageUrl) if its match delete that whole object which have that req.body.imageUrl and then update the document.
Please guide me on how to write such a query. Regards
Demo - https://mongoplayground.net/p/qpl7lXbKAZE
Use $pull
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
db.collection.update(
{},
{ $pull: { "imgDetails": { imageUrl: "xyz" } } }
)

how to query mongoDb with array of boolean fields?

My mongoose model schema looks like -
{
email: { type: String},
Date: {type: Date},
isOnboarded: {type: Boolean},
isVip: {type: Boolean},
isAdult: {type: Boolean}
}
In my frontend I have 3 checkboxes for "isVip", "isOnboarded" and "isAdult" options. If they are checked I'm adding them to an array, which I'll pass to the server. Let's say if "isVip" and "isAdult" are checked, I will pass [isVip, isAdult] in post api to server. Now how can I write a query to get all the documents with the fields in array as true i.e in above example how can I retrieve all docs with {isVip: true, isAdult:true}
I'm having trouble because the array values keep changing, it can be only one field or 3 fields. I couldn't find a way to give condition inside mongoose query.
User.find(
{ [req.query.array]: true},
{ projection: { _id: 0 } }
)
User is my mongoose model.
I want something like this (documents with the value 'true' for the fields given in the array) and 'req.query.array' is the array with field names I passed from frontend.
You have to create your object in JS and pass then to mongo in this way:
var query = {}
if(isVip) query["isVip"] = true;
if(isOnboarded) query["isOnboarded"] = true;
if(isAdult) query["isAdult"] = true;
And then you can use the mongoose method you want, for example:
var found = await model.find(query)
And this will return the document that matches the elements.
Also, note that this is to create and object to be read by the query, so you can use this into an aggregation pipeline or whatever you vant
Check the output:
var query = {}
query["isVip"] = true;
query["isOnboarded"] = true;
query["isAdult"] = true;
console.log(query)
Is the same object that is used to do the query here
{
"isVip": true,
"isOnboarded": true,
"isAdult": true
}
Also, to know if your post contains "isVip", "isOnboarded" or "isAdult" is a javascript question, not a mongo one, but you can use something like this (I assume you pass a string array):
var apiArray = ["isVip","isAdult"]
var isVip = apiArray.includes("isVip")
var isAdult = apiArray.includes("isAdult")
var isOnboarded = apiArray.includes("isOnboarded")
console.log("isVip: "+isVip)
console.log("isAdult: "+isAdult)
console.log("isOnboarded: "+isOnboarded)

save Embed docs as an object using mongoose?

I have a schema like this
const user = new Schema({
firstName: { type: String, required: true },
lastName: { type: String , required: true},
phone:{type: Number, unique true}
embeddedDocsAsJson: {} // not as an array
},
{ minimize: false }
)
I want to use embeddedDocsAsJson because of two reasons
In case of array a duplicate data can be pushed to array , if I use json it will not occur as I'll use unique id as json key
Retrieval will be faster as I don't have to iterate on the array . I can fetch it from the json key
Problem:
Firstly I'm inserting firstName and lastName phone.
And embeddedDocsAsJson is added while updating the docs below is my code for updating
let user = await User.findOne({phone: somenumber})
user.embeddedDocsAsJson.someId = someObject // getting error in this line because `user.embeddedDocsAsJson` is `undefined`
user.save()
I'm adding value to embeddedDocsAsJson while updating
EmbeddedDocs are by-default array if you want to save object in your collection below code will work.
let user = await User.findOne({phone: somenumber})
user.embeddedDocsAsJson = {}
user.embeddedDocsAsJson.someId = someObject // getting error in this line because `user.embeddedDocsAsJson` is `undefined`
user.save()

Mongodb Deep Embedded Object Array Query

Hi I am facing a problem in updating an embedded object array using mongoose!
Here is the Schema:
var event = {
eTime : [String]
};
var schedule = {
events: [event]
};
var group = {
gName: {type:String},
sDate: { type: Date, default: Date.now },
schedules: [schedule]
};
MainSchema {
id : String,
groups : [group]
};
The thing which I want to do is that to update the array of eTime in events with an object of schedules. I am using this query
db.demoDb.update({
'id': 'MongoDb',
'groups':{
$elemMatch:{
'gName':'noSql'
}
}
},
{
$push:{
'groups':{
'schedules':{
'events':{
'eTime':'01-Marach-15'
}
}
}
}
}
)
but the schedules->events->eventTime is not updating with a value!!!
What wrong I am doing here?
My Main Scenario is to find the id(MongoDB) with associated gName and then update its schedules array of it.
My find query is working great but can not update the schedules... and events can be many
If I'm reading your schema correctly, the core part is an array containing an array containing an array containing an array of strings. I think you would do much better "inverting" the schema so each document represents an event. Metadata grouping multiple events can be duplicated into each event document. An example:
{
"event" : "cookie bake-off",
"gName" : "baking",
"sDate" : ISODate("2015-03-02T21:46:11.842Z")
}
The update that you are struggling with translates into an insertion of a new event document in the collection.

Serialize ids when saving emberjs model

I have an emberjs application backed by a nodejs server and mongodb. Currently my database is sending documents with an '_id' field. I have the followign code to force Ember to treat '_id' as the primary key:
App.ApplicationSerializer = DS.RESTSerializer.extend({
primaryKey: '_id'
});
On the other hand i have two models related by a 'hasMany' relationship as such:
App.Player = DS.Model.extend({
name: DS.attr('string'),
thumbLink: DS.attr('string'),
activeGame: DS.belongsTo('game', { async: true }),
email: DS.attr('string'),
firstName: DS.attr('string'),
lastName: DS.attr('string'),
admin: DS.attr('boolean')
});
App.Game = DS.Model.extend({
name: DS.attr('string'),
active: DS.attr('boolean'),
players: DS.hasMany('player', { async: true })
});
The problem is that when i try to save the model ( this.get('model').save() )on my controller the ids are not serialized and the result is ember sending the following:
{"game":{"name":"Indie/Rock","active":false,"players":[],"_id":"53cbbf43daa978983ee0b101"}}
As you can see the players array is empty, and as a result, the server is saving that empty array which in fact is not correct. I am aware that it is possible to use { embedded: true } on the models and return the models with embedded documents from the server, but i want to preserve the async feature.
I have tried to extend the game serializer from EmbeddedRecordsMixing as the following:
App.GameSerializer = DS.ActiveModelSerializer
.extend(DS.EmbeddedRecordsMixin)
.extend({
attrs: {
players: {serialize: 'ids', deserialize: 'ids'},
}
});
But when i do so i get the following error from ember even though the ApplicationSerializer is suppossedly telling Ember to user _id as primary key:
Assertion Failed: Error: Assertion Failed: You must include an `id` for App.Game in a hash passed to `push`
My question is if it is possible to maintain the async features of ember-data while being able to serialize the document with the ids on it's relation and using _id as a primary key.
Thank you.
Ember Data is stupid in this aspect, if it's a ManyToOne relationship, it only includes the id from the belongsTo side. Honestly I've had it on my bucket list to submit a PR, but time is limited.
https://github.com/emberjs/data/commit/7f752ad15eb9b9454e3da3f4e0b8c487cdc70ff0#commitcomment-4923439
App.ApplicationSerializer = DS.RESTSerializer.extend({
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key;
var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany'
|| relationshipType === 'manyToOne') { // This is the change
json[payloadKey] = get(record, key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany relationships
}
},
});

Resources