Properties with default values in Mongoose schema are not persisting - angularjs

I have the following schema I've written using Mongoose:
var querySchema = mongoose.Schema({
quoteId: { type: String, default: '' },
zipcode: { type: String, default: '' },
email: { type: String, default: '' },
type: {type: String, default: ''},
isEmailChecked: { type: Boolean, default: true },
});
I provide values for only 3 properties in the querySchema assuming that the result of the fields will take default values when a new instance of query object is persisted:
var query = {};
query.quoteId = "1414775421426";
query.email = "myself#somewhere.com";
query.type = "Foo";
But following document is what I see as the result in the collection:
{
"_id" : ObjectId("5453c27d0e4c3f2837071856"),
"email" : "myself#somewhere.com",
"type" : "Foo",
"quoteId" : "1414775421426",
"__v" : 0
}
Should isEmailChecked and zipcode not be assigned their default values when a new instance of query object is persisted to the MongoDB database?
Following is how I am persisting an instance of the query object using ExpressJS/NodeJS:
app.post('/api/queries', function (req, res) {
QuoteQuery.create({
quoteId: req.body.query.quoteId,
type: req.body.query.type,
zipcode: req.body.query.zipcode,
email: req.body.query.email,
isEmailChecked: req.body.query.isEmailChecked,
}, function (err, query) {
if (err) {
res.send(err);
}
res.json(query);
});
});
Could somebody help me understand that why I got the isEmailChecked and zipcode properties in the resulting document in the MongoDB database?
I am using NodeJS, AngularJS and ExpressJS in my application along with MongoDB.

When you set mongoose model field it not use default value.
As workaround you can use underscore to extend mongoose model object with keys which exists in your query object like this:
_.extend(dbQueryObject, query);
Here is complete example:
var mongoose = require('mongoose');
var querySchema = mongoose.Schema({
quoteId: { type: String, default: '' },
zipcode: { type: String, default: '' },
email: { type: String, default: '' },
type: {type: String, default: ''},
isEmailChecked: { type: Boolean, default: true }
});
var db = mongoose.createConnection('mongodb://localhost:27017/stackoverflow',
{ server: { auto_reconnect: true } },
function(err) {
var QuerySchema = db.model('test', querySchema);
var query = {};
query.quoteId = "1414775421426";
query.email = "myself#somewhere.com";
query.type = "Foo";
QuerySchema.create({
quoteId: query.quoteId,
type: query.type,
zipcode: query.zipcode,
email: query.email,
isEmailChecked: query.isEmailChecked
}, function (err, query) {
process.exit(0);
});
});
Here is what in db:
{
"_id" : ObjectId("5453ce3c9f7e0d13c52abf61"),
"type" : "Foo",
"email" : "myself#somewhere.com",
"quoteId" : "1414775421426",
"__v" : 0
}

Related

How to add new property to mongoDb model?

Hello I am creating a project to show user changes in the PopulationCount data of all the coins according to their categories.
I created a NodeJS script to scrape the data from a coin website, and I have saved it in my MongoDB cloud database as shown below.
In the Front-End, I have created a React App as shown:
When user clicks on a coin category, it should display all the coins from today
Here is the code that relates to showing all the Coin's Categories in my route:
router.get(
"/categories",
asyncHandler(async (req, res) => {
const categories = await Coin.find().distinct(
"category",
(err, results) => {
res.json(results);
}
);
})
);
I am having the biggest problem/trouble with my life because I need to add new property to this document that calculates the difference of the PopulationCount from Today's Date and Yesterday's Date and then adding this new "Trend" property to the document.
So that I can display the Coin data from Today's date and the calculated "trend" property that determines if it there was a decrease or increase in value.
How can I achieve this? So far I have written this code, but I do not know where to go from here.
router.get(
"/categories/:category",
asyncHandler(async (req, res) => {
const { category } = req.params;
const fullName = category.replace(/-/g, " ");
// todays coins
const today = new Date(Date.now());
today.setHours(0, 0, 0, 0);
const todaysCoins = await Coin.find({
category: {
$regex: new RegExp(fullName, "i"),
},
createdAt: {
$gte: today,
},
}).lean();
res.json(todaysCoins);
// loop thru all todays coins
// compare to yesterdays coins
// loop thru array of today and compare to yesterday and add trend
})
// loop through yesterdays coins
const startYest = new Date(Date.now());
startYest.setHours(0, 0, 0, 0);
const oneDayAgo = startYest.getDate() - 1;
startYest.setDate(oneDayAgo);
const endYest = new Date(Date.now());
endYest.setHours(23, 59, 59);
const endYestDayAgo = endYest.getDate() - 1;
endYest.setDate(endYestDayAgo);
const yesterdayCoins = await Coin.find({
category: {
$regex: new RegExp(fullName, "i"),
},
createdAt: {
$gte: startYest,
$lt: endYest,
}
}).lean()
);
As Sharrzard Gh said, MongoDB doesn't allow you to add a new property to your model after it's been defined. Instead, use a structure like this, to define an initially empty property that you will use later to store the trend data.
const CoinSchema = new Schema({
specName: { type: String, required: true },
fullName: { type: String, required: true },
category:{ type: String, required: true },
coinName: { type: String, required: true },
trend: { type: String, required: true, default: '' } // <- Add this property
});
module.exports = mongoose.model("coins", CoinSchema);
You can change the trend data type to an array or object if you need to store more complex data or a series of data points for historical trend tracking, if you want.
Try something like this:
trend: { type: Object, required: true, default: {} }
or
trend: { type: [String] , required: true, default: [] }
I was able to add new properties in the model even after the creation of the model in Node.js using:
insertMany(table_data, { strict: false });
where table_data container the old data appended with the new properties. The strict: false did the magic.
Order Model in Node:
const mongoose = require ('mongoose');
const OrdersSchema = new mongoose.Schema({
sr_no :{type: Number, required:true},
customer_name :{type: String, required:true},
product_name: String,
codes: String,
code_date:{
type:Date,
default: Date.now()
},
design : String,
design_date :{
type:Date,
default: Date.now()
},
design_approval :{
type:String,
default: ''
},
design_approval_date :{
type:Date,
default: Date.now()
},
send_to_printer :{
type:String,
default: ''
},
send_to_printer_date :{
type:Date,
default: Date.now()
},
proof_approval :{
type:String,
default: ''
},
proof_approval_date :{
type:Date,
default: Date.now()
},
shipping : String,
ship_date :{
type:Date,
default: Date.now()
},
received :{
type:String,
default: ''
},
received_date :{
type:Date,
default: Date.now()
},
completed : String,
notes : String,
printing :{
type:String,
default: ''
},
printing_date :{
type:Date,
default: Date.now()
},
stapling :{
type:String,
default: ''
},
stapling_date :{
type:Date,
default: Date.now()
},
user_id :{type: Number, required:true}
},{strict: false});
OrdersSchema.index({ sr_no: -1 });
const Orders = mongoose.model(
'Orders',
OrdersSchema
);
module.exports = Orders;
In Mongo Compass the first record appeared like:
And another record in the same collection was:

How to insert record automatically in mongodb (nodejs, express, mongoose)

I am working on a team-based project. I created a new collection with some records (inserted manually). Is there any script or code to insert these records automatically from within the code, so that my when my colleague will work they do not need to insert those records again.
Code:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ServiceCategoryTypeSchema = new Schema({
_id: {type: String},
name:String
}, {
collection:'service_category_type',
timestamps:{createdAt:'created_at', updatedAt:'updated_at'}
}
);
module.exports = {
getModel: function(db){
return db.model("ServiceCategoryType", ServiceCategoryTypeSchema)
},
schema:ServiceCategoryTypeSchema
};
This is the record, I am thinking to add automatically,
{
"_id" : "Inventory",
"name" : "Inventory"
}
{
"_id" : "Non-inventory",
"name" : "Non-inventory"
}
{
"_id" : "Service",
"name" : "Service"
}
When you have your model in, say, YourModel, then you should be able to save your data that you have in, say, yourData with something like this:
new YourModel(yourData).save(function (error, data) {
// handle errors, log success etc.
});
You can do it for as many pieces of data as you want.
When you populate the database with some data it may be a good idea to first check if the database is not populated yet.
Example
Here is a working example program that saves such data - I changed the database and collection names so that you won't mess with your real database when you run it:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var P = mongoose.Promise = require('bluebird');
mongoose.connect('mongodb://localhost/poptest');
var TestModel = mongoose.model('TestModel', new Schema({
_id: String,
name: String
}, {
collection: 'testcollection',
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
}
));
var sampleData = [
{_id: "Inventory", name: "Inventory"},
{_id: "Non-inventory", name: "Non-inventory"},
{_id: "Service", name: "Service"}
];
P.all(sampleData.map(i => new TestModel(i).save()))
.then(() => console.log('Data saved'))
.catch((err) => console.log('Error: ' + err))
.finally(process.exit);
You need to install mongoose and bluebird for it to work:
npm i mongoose bluebird
It creates 3 documents in the poptest database on localhost. You can verify it by running:
mongo poptest
and querying the testcollection collection:
db.testcollection.find();
You should get something like:
> db.testcollection.find().pretty();
{
"_id" : "Inventory",
"updated_at" : ISODate("2016-09-14T16:13:37.374Z"),
"created_at" : ISODate("2016-09-14T16:13:37.374Z"),
"name" : "Inventory",
"__v" : 0
}
{
"_id" : "Non-inventory",
"updated_at" : ISODate("2016-09-14T16:13:37.377Z"),
"created_at" : ISODate("2016-09-14T16:13:37.377Z"),
"name" : "Non-inventory",
"__v" : 0
}
{
"_id" : "Service",
"updated_at" : ISODate("2016-09-14T16:13:37.377Z"),
"created_at" : ISODate("2016-09-14T16:13:37.377Z"),
"name" : "Service",
"__v" : 0
}
This solution worked for me: https://github.com/Automattic/mongoose/issues/6326
'use strict'
const mongoose = require('mongoose')
const uri = 'mongodb://localhost/test'
const db = mongoose.createConnection(uri)
const Schema = mongoose.Schema
const testSchema = new Schema({
name: String,
age: Number
})
const Test = db.model('test', testSchema)
const test = new Test({ name: 'Billy', age: 31 })
db.once('connected', function (err) {
if (err) { return console.error(err) }
Test.create(test, function (err, doc) {
if (err) { return console.error(err) }
console.log(doc)
return db.close()
})
})

Mongoose how to save document inside an array

I have a model which looks like this:
User.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var memberSchema = new Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
min: 8
}
});
var userSchemaPrimary = new Schema({
team_code : {
type: String,
required: true,
unique: true
},
members:[memberSchema],
});
var User = mongoose.model('User', userSchemaPrimary);
module.exports = User;
And this is how am trying to save
var User = require('../models/user');
var newTeam = new User({
team_code : 'CODE01',
members:
{
email: req.body.email,
password: pass
}
});
newTeam.save(function(err) {
if (err) throw err;
console.log('User saved successfully!');
return res.send("Done");
});
When executed, throws model validation error.
Well I tried to save data without the array documents, then its saves successfully. But when I try to save the array (array "members"), it throws validation error.
I WANT TO
Store data in the following way:
{
team_code: "CODE01",
members: [
{
email: "test01#email.com",
password: "11111111"
},
{
email: "test02#email.com",
password: "22222222"
}
{
email: "test03#email.com",
password: "33333333"
}
]
}
I dont understand what is going wrong. Any help is appreciated.
You are assigning object to members field, but it's an array
var newTeam = new User({
team_code : 'CODE01',
members: [{
email: req.body.email,
password: pass
}] // <-- note the array braces []
});

Possible circular reference in mongoose

I have a problem with circular dependency when I need to SAVE a 'document'.
My application is all Restfull with the interface via AngularJS.
On the screen to create a COMPANY, you can create OBJECTS and SERVICES. In the creation of the SERVICES screen, it must associate a created OBJECT.
The problem is that the OBJECT created has not yet persisted, so I don't have a _id. Thus it is not possible to reference it in SERVICE. Only when I have an OBJECT persisted, I can associate it in company.services[0].object.
Any suggestion?
This is what I need to be saved in MongoDB. Look at the reference to the OBJECT "5779f75a27f9d259248211c7" in SERVICE.
/* 1 */
{
"_id" : ObjectId("5749bb92bf8145c97988e4a9"),
"name" : "company 1",
"services" : [
{
"_id" : ObjectId("5764cb2c00d00cf10c9c41c6"),
"description" : "service 1",
"object" : ObjectId("5779f75a27f9d259248211c7"),
}
],
"objects" : [
{
"_id" : ObjectId("5779f75a27f9d259248211c7"),
"description" : "object 1",
}
]
}
And this is my Schema:
var objectSchema = new mongoose.Schema({
description: {
type: String,
trim: true,
unique: true,
required: 'Description is required'
}
})
var serviceSchema = new mongoose.Schema({
description: {
type: String,
trim: true,
required: 'Description is required'
},
object: {
type: mongoose.Schema.ObjectId,
ref: 'Object'
},
})
var companySchema = new mongoose.Schema({
name: {
type: String,
default: '',
trim: true,
unique: true,
required: 'Name is required'
},
guarda_documentos: {
services: [serviceSchema],
objects: [objectSchema],
},
});
mongoose.model('Company', companySchema);
mongoose.model('Object', objectSchema);
You would need to persist your object first and once this is done, use the returned _id to then persist your service. This is an async process.
// Simplified code concept
// Create a new object
var o = new Object()
o.description = 'foo'
...
// Create a new service
var s = new Service()
// Save object and return it (will now have an _id)
o.save(function(err, doc) {
// Add object reference to service and save
s.object = doc._id
s.save(function(err, res) {
// Call your controller or whatever callback here
})
})
On another note don't use "Object" as the name of your doc. It already defined in Javascript.

mongoose update with push operations on array and set operation on object

I have this mongoose schema
var ContactSchema = module.exports = new mongoose.Schema({
name: {
type: String,
required: true
},
phone: {
type: Number,
required: true,
},
messages: [
{
title: {type: String, required: true},
msg: {type: String, required: true}
}],
address:{ city:String,
state:String
}
});
I have initially the collection set with name and phone field. I need to update the collection with new messages into messages array and new address into address object. the function must also need to handle any single operation, ie in some case i have only update to messages array or updates to both name and address. so how i can i do all operations in a single function.
var messages= {
title: req.body.title,
msg: req.body.msg
}
Model.findOneAndUpdate({'_id': req.body.id,},{$push: {messages:message}},{upsert: true}, function (err, data) {
if (err) {
return res.status(500).send(err);
}
if (!data) {
return res.status(404).end();
}
return res.status(200).send(data);
});
You could try use both the $set and $push operators in your update object. Suppose, for example, you want to update both name and address fields in one single operation, use the $set on the name field and a $push operation to the address array:
var messages= {
title: req.body.title,
msg: req.body.msg
},
query = {'_id': req.body.id},
update = {
$set: {name: req.body.name},
$push: {messages: message}
},
options = {upsert: true};
Model.findOneAndUpdate(query, update, options, function (err, data) {
if (err) {
return res.status(500).send(err);
}
if (!data) {
return res.status(404).end();
}
return res.status(200).send(data);
});

Resources