I am attempting to add a form result to an existing client in a collection and all form data variables being passed are added successfully, however, a default date variable is not being created and saved despite being in the schema.
Here is the schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const FormSchema = new Schema({
formID: {
type: String
},
formName: {
type: String
},
date_completed: {
type: Date,
default: Date.now
},
formData: {
type: JSON
}
});
const ClientSchema = new Schema({
clientID: {
type: String,
required: true,
unique: true
},
dob: {
type: Date,
required: true
},
formResults: {
tags: [
{
type: FormSchema
}
]
}
});
module.exports = Client = mongoose.model('client', ClientSchema);
And here is the method posting the form results:
router.post('/:id', auth, (req, res) => {
Client.update(
{ clientID: req.params.id },
{
$push: {
formResults: {
$each: [
{
formID: req.body.formID,
formName: req.body.formName,
formData: req.body.formData
}
]
}
}
}
)
.then(() => res.json({ success: true }))
.catch(
err => res.status(404).json({ success: false }) && console.log(err)
);
});
I have tried forcing the date by passing date_completed: Date.now with the other form variables but this makes no difference. The results are still saved with no date variable listed. I have also tried dropping the collection and recreating it, this gave no changes. And I have checked the indexes for the collection, for which there is only _id and clientID.
Here is the data in saved in the database when executed and showing there is no date_completed: value.
Stored Data
At first glance your code is correct and should have no problem as it complies with the documentation and tutorials of mongoose, you can test this code:
// Create Schema
const FormSchema = new Schema({
formID: {
type: String
},
formName: {
type: String
},
date_completed: {
type: Date,
default: function() {
if (!this.date_completed) {
return Date.now();
}
return null;
}
},
formData: {
type: JSON
}
});
or:
var minuteFromNow = function(){
var timeObject = new Date();
return timeObject;
};
// Create Schema
const FormSchema = new Schema({
formID: {
type: String
},
formName: {
type: String
},
date_completed: {
type: Date,
default: minuteFromNow
},
formData: {
type: JSON
}
});
Let us also say this null is a valid value for a Date property, unless you specify required. Defaults only get set if the value is undefined, not if its falsy.
Honestly, I wasn't able to find any reason why it was not working. I waited a few days and the issue fixed itself. I don't believe there was anything wrong with the code, I think the issue was to do with MongoDB Atlas not updating results and displaying the dates that were being created but again I have no idea why this would be the case.
Related
the question is to save unique value generated from multiple sources into one Schema. This schema is a placeholder for all individual data and there should not be any repeat.
(function() {
ContactUniqueMarketingSchema = module.exports = mongoose.Schema({
contacts: [{
displayName: { type: String },
emails: [Object],
familyName: { type: String },
firstName: { type: String },
id: { type: String },
middleName: { type: String },
phoneNumbers: [Object],
rawId: { type: String },
location: {
type: Object,
properties: {
type: {
type: String,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
},
coordinates: {
type: [Number],
default: [0, 0]
}
}
},
created_at: { type: Date, default: Date.now },
}],
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now }
});
ContactUniqueMarketingModel = module.exports = mongoose.model("ContactUniqueMarketingModel", ContactUniqueMarketingSchema);
})()
below is the code as how I am saving it. however I do try to filter the data beforehand but in few edge cases duplicates values do come in. the filter function only filter from the JSON object. however there is no way of knowing from Schema
(function() {
function transformContact(contacts) {
var transformedContact = [];
if (contact) {
contact.forEach(function(tupleContact, index) {
});
}
};
function getUniqueContact(contacts) {
log('Get Unique Contact Value :');
var UniqueContacts = [];
var contactMap = new Map();
contacts.forEach(row => {
if (!contactMap.has(row.phoneNumbers[0].value.toString())) contactMap.set(row.phoneNumbers[0].value.toString(), row);
});
for (var value of contactMap.values()) {
UniqueContacts.push(value);
};
return UniqueContacts;
}
DeviceInformationSchema.pre('findOneAndUpdate', function(next) {
log('DeviceInformationSchema findOneAndUpdate Hook :');
var device = this;
var contactToSave = [];
device.contacts = getUniqueContact(device.contacts);
contactToSave.push(device.contacts);
var contactSaveTuple = new ContactUniqueMarketingModel(contactToSave);
contactSaveTuple.save(function(errSave, saved) {
if (errSave) {
log('Error Occured Saving New Data :');
}
log('Successfully Added Data To ContactUniqueMarketingModel Via Save');
next();
});
});
DeviceInformationSchema.pre('save', function(next) {
log('DeviceInformationSchema Save Hook :');
var device = this;
var contactToSave = [];
device.contacts = getUniqueContact(device.contacts);
contactToSave.push(device.contacts);
var contactSaveTuple = new ContactUniqueMarketingModel(contactToSave);
contactSaveTuple.save(function(errSave, saved) {
if (errSave) {
log('Error Occured Saving New Data :');
}
log('Successfully Added Data To ContactUniqueMarketingModel Via Save');
next();
});
});
DeviceInformationSchema.pre('update', function(next) {
log('DeviceInformationSchema update Hook :');
var device = this;
var contactToSave = [];
device.contacts = getUniqueContact(device.contacts);
contactToSave.push(device.contacts);
var contactSaveTuple = new ContactUniqueMarketingModel(contactToSave);
contactSaveTuple.save(function(errSave, saved) {
if (errSave) {
log('Error Occured Saving New Data :');
}
log('Successfully Added Data To ContactUniqueMarketingModel Via Update');
next();
});
});
// });
})()
Above schema, values are inserted into the common Schema which contains only contacts. The save mechanism is performed from hooks from another Schema
Please suggest
I almost have the desired functionality but it's not exactly what I wanted to approach.
I have two model schema, Control and SubControl. The SubControl is referenced in the Control model. I want to post the control model + a reference of the SubControl.
My post method:
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
const subControl = new SubControl({...req.body});
const subControlDoc = await subControl.save();
const control = new Control({...req.body});
control.subControl.push(subControlDoc._id);
const savedControl = await control.save();
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl
});
} catch (error) {
return res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
My Control Schema:
const ControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
mainControl: {
type: String
},
subControl: [{
subControlNo: {type: Mongoose.Schema.Types.String, ref: 'SubControl'}
}],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Control', ControlSchema);
My SubControl schema:
const SubControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('SubControl', SubControlSchema);
Postman:
{
"mainControl": "nn",
"controlDescription": "controldescription",
"subControl":
[
{
"subControlNo": "1-2"
},
{
"subControlNo": "1-2-1"
}
]
}
Result I'm getting:
Question: Why am I getting 3 object id's although I inserted 2 and why only the last object ID is saved in my SubControl database? I this the way to add array of object id's or not?
Basically I'm trying to get the time and the entity changed in a particular model when ever the update method is called.
This is my model I want to keep track of:
const mongoose = require("mongoose");
const modelSchema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
name: {
type: String,
required: true,
},
note1: String,
note2: String,
note3: String,
images: {
type: Array,
required: true
},
status: {
enum: ['draft', 'pending_quote', 'pendong_payment', 'in_production', 'in_repair', 'pemding_my_review', 'fulfilled'],
type: String,
default: "draft"
},
price: {
type: mongoose.Schema.Types.ObjectId,
ref: "Price",
}
}, {
timestamps: true,
})
module.exports = mongoose.model("Model", modelSchema)
And this is the method I call to update the status:
exports.updateModel = async (req, res) => {
try {
let id = req.params.id;
let response = await Model.findByIdAndUpdate(id, req.body, {
new: true
})
res.status(200).json({
status: "Success",
data: response
})
} catch (err) {
res.status(500).json({
error: err,
msg: "Something Went Wrong"
})
}
}
you can add a new field in your schema like:
logs:[{
entity: String,
timeStamp: Date
}]
Then updating it basing on your current code:
let id = req.params.id;
// I don't know whats in the req.body but assuming that it
// has the correct structure when passed from the front end
let response = await Model.findByIdAndUpdate(id,
{
$set:req.body,
$push:{logs:{entity:'your entity name here',timeStamp:new Date()}}
}, {
new: true
})
I am not a totally new populate user but now I do not know what's wrong.
Here I need to populate my designerId which is type of ObjectId. Take a look at my route.
ordersAdminRouter.route('/customorder/add')
.post(function(req, res){
body = req.body;
console.log(body);
CustomOrders.create(body, function(err, saved){
if (err) throw err;
Designs.findByIdAndUpdate(saved.designId, {$set: {status: 'Order Sent'}}, {new: true}).exec()
.then(function(updated){
return CustomOrders.findById(saved._id).populate(saved.designId).exec();
})
.then(function(orders){
res.json(orders);
})
.then(undefined, function(err){
console.log(err);
})
});
});
saved._id is working because when I remove the populate, it returns the document that I need without the populated document of course.
Take a look at my schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var customOrderSchema = new Schema({
designId: { type: Schema.Types.ObjectId, ref: 'customDesigns' },
size: { type: String },
quantity: { type: Number },
totalPrice: { type: Number },
paymentMode: { type: String },
rcpt_img: { type: String },
refNumber: { type: String }
});
module.exports = mongoose.model('customOrders', customOrderSchema);
Here is my customDesigns schema.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var customDesignSchema = new Schema({
item_name: { type: String },
price: { type: Number, default: 0 },
img_url_front: { type: String },
img_url_back: { type: String },
designer: { type: Schema.Types.ObjectId, ref: 'users' },
color: { type: String },
designDate: { type: Date, default: Date.now() },
status: { type: String, default: 'For Qoutation' }
});
module.exports = mongoose.model('customDesigns', customDesignSchema);
I need to admit that I am new to promises on mongoose & express and this is my first time doing so. But using populate, i use it more than I can think of. Any suggestions?
return CustomOrders.findById(saved._id).populate('designId').then(.. your code);
By the way, you dont must use .exec() then you want execute your query, .then executes query as well. You can skip .exec()
http://mongoosejs.com/docs/populate.html
http://mongoosejs.com/docs/api.html#query_Query-populate
I have a model called Shop whos schema looks like this:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ShopSchema = new Schema({
name: { type: String, required: true },
address: { type: String, required: true },
description: String,
stock: { type: Number, default: 100 },
latitude: { type: Number, required: true },
longitude: { type: Number, required: true },
image: String,
link: String,
tags: [{ type: Schema.ObjectId, ref: 'Tag' }],
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
module.exports = mongoose.model('Shop', ShopSchema);
I want to use the array tags to reference to another model via ObjectId obviously. This set up works fine when I add ids into the property via db.shops.update({...}, {$set: {tags: ...}}) and the ids get set properly. But when I try to do it via the Express.js controller assigned to the model, nothing gets updated and there even is no error message. Here is update function in the controller:
// Updates an existing shop in the DB.
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Shop.findById(req.params.id, function (err, shop) {
if (err) { return handleError(res, err); }
if(!shop) { return res.send(404); }
var updated = _.merge(shop, req.body);
shop.updatedAt = new Date();
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, shop);
});
});
};
This works perfect for any other properties of the Shop model but just not for the tags. I also tried to set the type of the tags to string, but that didn't help.
I guess I am missing something about saving arrays in Mongoose?
It looks like the issue is _.merge() cannot handle merging arrays properly, which is the tags array in your case. A workaround would be adding explicit assignment of tags array after the merge, if it is ok to overwrite the existing tags.
var updated = _.merge(shop, req.body);
if (req.body.tags) {
updated.tags = req.body.tags;
}
Hope this helps.. If the workaround is not sufficient you may visit lodash forums.