save unique json key value pair in mongoose schema - node.js

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

Related

MongoDB not adding default date for nested Schemas?

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.

Intersection of key values between 2 different collections in MongoDB

I have 2 collections: bookings and timeslots.
models/booking.js:
var mongoose = require ('../config/db');
var Schema = require('mongoose').Schema;
var ObjectId = Schema.ObjectId;
var bookingSchema = new Schema({
start: {
type: Number,
required: true
},
end: {
type: Number,
required: true
},
date: {
type: Date,
required: true,
default: Date.now
}
});
models/time_slot.js:
var mongoose = require ('../config/db');
var Schema = require('mongoose').Schema;
var ObjectId = Schema.ObjectId;
var timeSlotSchema = new Schema({
start: {
type: Number,
required: true
},
end: {
type: Number,
required: true
},
date: {
type: Number,
required: true,
default: Time.Today
},
enabled: {
type: Boolean,
required: true,
default: true,
},
pickup: {
type: Boolean,
required: true,
default: true,
}
});
Both have a field start in common. I would like to be able to get the entries from the collection timeslots in which the value of start has occurred in bookings.
I have tried:
controllers/time_slot.js:
var timeSlotModel = require('../models/time_slot').model;
var Booking = require('./booking');
Booking.getBookings({}, function(err, bookings) {
if (err) {
console.error(err);
} else {
timeSlotModel.find({start: bookings.start}, function(err, slots) {
if (err) {
console.error(err);
} else {
return next(null, slots);
}
}
}
But that doesn't work, unsurprisingly, and I get the error:
MongooseError: Cast to number failed for value "undefined" at path "start"
You can do it like this:
Booking.getBookings({}, function(err, bookings) {
if (err) {
console.error(err);
} else {
// build array with unique "start" values from bookings
var starts = bookings
.map(booking => booking.start)
.filter((val, i, self) => self.indexOf(val) === i)
// find by these start values
var query = {start: {$in: starts}}
timeSlotModel.find(query, function(err, slots) {
if (err) {
console.error(err);
} else {
return next(null, slots);
}
}
}

Mongoose post update middleware not working

I am use "mongoose": "^4.1.2". I have try to update a matchRate field when after a document being updated. But it doesn't work either not throw an any errors.
Here is code:
list.model.js
'use strict';
var mongoose = require('bluebird').promisifyAll(require('mongoose'));
import { Schema } from 'mongoose';
var ListSchema = new Schema({
name: { type: String, required: true },
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
emails: [],
emailColRef: String,
matchCount: Number,
totalCount: Number,
matchRate: Number,
state: {
type: String,
enum: ['pending', 'complete', 'invalid']
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
default: {
type: Boolean,
default: false
}
});
ListSchema
.virtual('count')
.get(() => this.emails.length);
ListSchema
.post('update', function() {
// this.update({},{ $set: { matchRate: this.matchCount / this.totalCount } });//Not working
//////-------------OR---------------//////
// this.matchRate=this.matchCount / this.totalCount;//Not working
console.log(this.matchCount);//undefined
console.log(this.totalCount);//undefined
console.log(this.matchRate);//undefined
});
export default mongoose.model('List', ListSchema);
list.controller.js
.....
.....
.....
var newList = {};
newList.name = name;
newList.emails = emails;
newList.emailColRef = emailColRef;
newList.state = status;
newList.matchCount = matchCount;
newList.totalCount = totalCount;
var query = { name: req.body.name };
List.update(query, newList, function(err, doc) {
// index(req, res);
if (err) {
console.log("Error in list update ", err)
return;
}
fs.unlink(req.file.path, function(err) {
if (err) {
console.log("Error in removing file", err)
return;
}
});
console.log('Update list with match status');
});

mongoose mongo.js save array with array to collection

I have this "schema" in mongoose, an array in my dictionary and have other embedded array,
I can save if no embedded object is present, how to save embedded objects?
var ReportSchema = new Schema({
appVersion: { type: String, required: true},
osVersion: { type: String, required: true},
deviceType: { type: String, required: true},
userID: { type: String, required: true},
sessionIDtimestamp: { type: String, required: true},
eventItem : [new Schema ({
eventType:{type :String},
startTime:{type :String},
endTime:{type :String},
params:[new Schema ({
val:{type :String}
})]
})]
});
on my router:
apiRouter.route('/report')
.post(function(req, res) {
var report = new Report();
report.appVersion = req.body.appVersion;
report.osVersion = req.body.osVersion;
report.deviceType = req.body.deviceType;
report.userID = req.body.userID;
report.sessionIDtimestamp = req.body.sessionIDtimestamp;
for (var i = req.body.events.length - 1; i >= 0; i--) {
var requestStringa = util.inspect(req.body.events, {showHidden: false, depth: null});
console.log("entro :"+requestStringa);
};
report.save(function(err) {
if (err) {
return res.send(err);
}
res.json({ message: 'report created!' });
});
})
also i dont think that way to enumerate the array is nice?
edit
the log of events
entro :[ { eventType: 'Account_Rated_Pressed',
startTime: '1435819399',
endTime: '1435819399',
params: [ { paramKey: 'rating', paramValue: '5' } ] },
{ eventType: 'RateableDetail',
startTime: '1435819399',
endTime: '1435819399',
params: [ { paramKey: 'rating', paramValue: '5' } ] } ]
how to save my embedded objects cheers
For saving embedded documents, just assign the array field eventItem the request object value as follows:
apiRouter.route('/report')
.post(function(req, res) {
var report = new Report();
report.appVersion = req.body.appVersion;
report.osVersion = req.body.osVersion;
report.deviceType = req.body.deviceType;
report.userID = req.body.userID;
report.sessionIDtimestamp = req.body.sessionIDtimestamp;
report.eventItem = req.body.events;
report.save(function(err) {
if (err) {
return res.send(err);
}
res.json({ message: 'report created!' });
});
})
In the instance that req.body.event is an object not an array, you would then need to use the JavaScript push() method to push the object to the array. Say for example, if req.body.event has the structure
{
eventType: 'Account_Rated_Pressed',
startTime: '1435819399',
endTime: '1435819399',
params: [ { paramKey: 'rating', paramValue: '5' } ]
}
you can then do
apiRouter.route('/report')
.post(function(req, res) {
var report = new Report();
report.appVersion = req.body.appVersion;
report.osVersion = req.body.osVersion;
report.deviceType = req.body.deviceType;
report.userID = req.body.userID;
report.sessionIDtimestamp = req.body.sessionIDtimestamp;
report.eventItem.push(req.body.event);
report.save(function(err) {
if (err) {
return res.send(err);
}
res.json({ message: 'report created!' });
});
})

Mongoose: value from Model

I have the following model:
var requestSchema = new Schema({
description: { type: String, required: true },
country: { type: String, index: true },
shipping: [shipping],
deliveryLoc: { type: String, index: true },
price: { type: Number, default: 0 },
})
I now want to get the price using mongoose and I am not sure which command I have to use.
I tried:
var pricy = _.first(_.where(request.price));
and it does not work, I get undefined even through through other queries in the same file I can get "shipping".
Getting the shipping type works with the following command:
var shipping = _.first(_.where(request.shipping, { type: shippingType }));
Am I using the wrong command?
You should be able to use the select method as follows:
// find a request
var query = Request.findOne();
// selecting the `price` field
query.select('price');
// execute the query at a later time
query.exec(function (err, request) {
if (err) return handleError(err);
console.log('The price is $%s.', person.price) // The price is $6.92
});
or if passing a callback:
var Request = mongoose.model('Request', requestSchema);
// find each request with a country matching 'Zimbabwe', selecting the `price` field
Request.findOne({ 'country': 'Zimbabwe' }, 'price', function (err, request) {
if (err) return handleError(err);
console.log('The price is $%s.', request.price) // The price is $6.92.
});
First, you need to create your schema like that:
var items = new Schema({
description: { type: String, required: true },
country: { type: String, index: true },
shipping: [shipping],
deliveryLoc: { type: String, index: true },
price: { type: Number, default: 0 },
});
After that you need to compile the new schema and add it to the database:
items = mongoose.model("Items", items); // The table name will be "Items"
When the model is created, you can execute your query (find or findOne):
items.findOne({price: request.price}, function (error, item) {
if (error) {
console.log(error);
} else {
console.log(item);
}
});
The full code:
var mongoose, Schema;
mongoose = require("mongoose");
Schema = mongoose.Schema;
var items = new Schema({
description: { type: String, required: true },
country: { type: String, index: true },
shipping: [shipping],
deliveryLoc: { type: String, index: true },
price: { type: Number, default: 0 },
});
items = mongoose.model("Items", items);
items.findOne({price: request.price}, function (error, item) {
if (error) {
console.log(error);
} else {
console.log(item);
}
});

Resources