mongoose insert data with promise - node.js

My goal is to insert a new country (with incremented country_id) into the db if it doesn't exist. In that case I try to get the max country_id and insert a new country with country_id + 1. Otherwise I don't do anything.
readFile is a promise to readfile,
filetoArray changes that file content to an array,
processMap processes each array element and decide if we store the info to mongodb or not
The problem is:
promise.promisifyAll(Country.findOne({}).sort({'zid' : -1}).exec()
always gives me the same result even when some data are already inserted into the database...
Any suggestions are greatly appreciated. Thanks.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CountrySchema = new Schema({
zn: {type: String, required: true},
zid: {type: Number, required: true}
});
var promise = require('bluebird');
function processMap(data){
return promise.bind(data).then(insertCountry);
}
var insertCountry = function() {
var googledata = this; // from bind promise
return promise.promisifyAll(Country.findOne({zn: googledata.country}).exec())
.then(function(dbdata){ return {dbdata: dbdata, googledata: googledata}; })
.then(insertCountryIfNotExist)
}
var insertCountryIfNotExist = function(data){
return promise.promisifyAll(Country.findOne({}).sort({'zid' : -1}).exec())
.then(function(d){
var newc = new Country({zn: data.googledata.country, zid: d.zid + 1});
return promise.promisifyAll(newc.saveAsync())
});
}
// main code is here
readFile(file)
.then(filetoArray)
.map(processMap, {concurrency: 1}) // end of then
.then(function(data){
console.log('done');
})

Actually Exec returns a promise inherited from mpromise, there's no need to use bluebird on your case or if you want to use bluebird, then don't mix the mongoose promises with blue bird.
some example:
var insertCountry = function() {
var googledata = this;
return Country.findOne({zn: googledata.country}).exec()
.then(function(dbdata){
return {dbdata: dbdata, googledata: googledata};
})
.then(function(data){
return Country.findOne({}).sort({'zid' : -1}).exec()
.then(function(d){
var newc = new Country({zn: data.googledata.country, zid: d.zid + 1});
return newc.save();
})
})
}

Related

Saving an array to MongoDB database

Let's say I have a schema for my MongoDb collection.
module.exports = (mongoose, Schema) => {
let eventSchema = new Schema({
name: String
values: ???
});
return mongoose.model('Event', eventSchema);
};
I receive a json like this one:
{"1965": 10000000, "1966": 20000000, "1967": 300000}
I want this array to be in the "values" field of the eventSchema. How do I save it to my db?
Years vary, and the number of objects in array is always different.
Try something like this:
const payload = { name : "test" , values : {"1965": 10000000, "1966": 20000000, "1967": 300000}
}
const event = new Event(payload)
event.save(function (err) {
if (err) return console.log(err);
// saved!
});
and make sure your schema is :
let eventSchema = new Schema({
name: String
values: Object
});

Mongoose field reset

I have a mongoose schema that looks like this:
var mongoose = require('mongoose');
var _ = require('lodash');
var Schema = mongoose.Schema;
var shopSchema = new mongoose.Schema({
name: {type: String, trim: true},
description: {type: String, trim: true},
rating: Number,
ratingsData: [{type: Number}]
});
shopSchema.methods.rate = function(rating){
this.ratingsData.push(rating);
this.rating = _.mean(this.ratingsData);
return this.ratingsData;
}
module.exports = mongoose.model('Shop', shopSchema);
The rate method is supposed to append a value passed to it to the ratingsData field and then return the average of that array. The problem I'm having is that everytime the method is called, this.ratingsData is just an empty array. The previous values aren't saved for some reason. Therefore the average I get is always the rating passed to the method.
What am I doing wrong?
You just didn't save the schema object, you need something like this:
shopSchema.methods.rate = function(rating, clb){
this.ratingsData.push(rating);
this.rating = _.mean(this.ratingsData);
this.save(function(err, result){
if(err) throw err;
return clb(result.ratingsData);
})
};
or if you use Promise:
shopSchema.methods.rate = function(rating){
this.ratingsData.push(rating);
this.rating = _.mean(this.ratingsData);
return this.save()
.then(result=>{
return result.ratingsData
})
.catch(err=>{
throw err;
})
};

save() not working with statics in mongoose

Below are various methods i tried to save documents but did not work. what am i doing wrong? Is it the correct way to use static? Is method needed here? If yes how will it be implemented in this situation?
Method 1:
userSchema.statics.saveUser = function(data, callback){
data.save(callback);
};
Result - save is not a function
Method 2:
userSchema.statics.saveUser = function(data, callback){
data = new userSchema(data);
data.save(callback);
};
Result - userSchema is not a function
Method 3:
userSchema.statics.saveUser = function(data, callback){
var user = new user(data);
data.save(callback);
};
var user = Mongoose.model('user', userSchema);
Result - user is not a function
Edit
Even the below methods does not seem to be working
Method 4:
userSchema.statics.saveUser = function(data, callback){
var user = new this(data);
user.save(callback);
};
Method 5: JohnnyHK suggested way
userSchema.statics.saveUser = function(data, callback){
var user = new this();
user.data = data;
user.save(callback);
};
userSchema is like this
var db = require('../database');
var Mongoose = db.Mongoose;
require('mongoose-long')(Mongoose);
var SchemaTypes = Mongoose.Schema.Types;
var userSchema = new Mongoose.Schema({
_id:{ type: String, required: true, unique:true },
// many fields with type as string and number
.
.
.
Number:{ type: SchemaTypes.Long, min: 0, default: 0},
});
// query functions here
var user = Mongoose.model('user', userSchema);
// exporting model here
Everything works fine if use this.create(data, callback); instead of save but i want to use save for some reasons.
Data before using it for save
[ { _id: '2A864493-52614B19',
name: 'xyz',
date: 'some date',
...
...
...
city: 'adf'
} ]
You need to create an instance of your model, because the save method is only available for instance.
var User = mongoose.model('user', UserSchema);
UserSchema.statics.saveUser = function(data, callback){
var user = new this(data);
user.save(callback);
};
And please, avoid duplication of variables with adding some uppercase. It's more readable and less hazardous.
Mongoose documentation : http://mongoosejs.com/docs/models.html

mongo insert in nodejs for loop only inserting one from array

im building an application to collect votes for a live event.
the api doesnt give us option to select users from a time frame so im polling the endpoint every second.
i currently have 13 entries that return from the endpoint, i parse them into and array and for loop around them setting my mongoose schema with the attributes and trying to save them, but when i do
db.votes.count() my result is always 1
my node module looks like
var express = require('express');
var unirest = require('unirest');
var voteSchema = require(GLOBAL.rootdir + '/modules/voting/models/votes');
var seconds = 0;
var interval = 1000;
express({
votePoller : setInterval(function () {
seconds++;
if (typeof GLOBAL.accessToken != 'undefined') {
var Request = unirest.get('https://api.domain.io/api/v1/guests');
Request
.header('Accept', 'application/json')
.header('Content-Type', 'application/json; charset=utf-8')
.header('Authorization', 'Bearer ' + GLOBAL.accessToken)
.end(function (response) {
if(response.code === 200){
var votesModel = new voteSchema;
var payloadArray = JSON.parse(response.raw_body);
for(var i in payloadArray.guests){
console.log(i);
console.log(payloadArray.guests[i]);
votesModel.ctid = payloadArray.guests[i].id;
votesModel.email = payloadArray.guests[i].username;
votesModel.voteStatus = 0;
votesModel.createdAt = new Date(1000 * payloadArray.guests[i].created_at);
votesModel.save(function(err) {
if (err) {
console.log(err);
console.log({ message: err });
} else {
console.log({ message: 'vote saved' });
}
});
console.log('Done');
}
}
});
}
console.log(seconds);
}, interval)
});
var votePoller = express;
module.exports = votePoller;
my mongoose model is
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var votesSchema = new Schema({
ctid: { type: String, required: true, unique: true },
fullName: { type: String},
email: { type: String, required: true, unique: true },
mobileNumber: { type: String },
vote: { type: Number},
voteStatus: Boolean,
createdAt: Date
});
var Votes = mongoose.model('Votes', votesSchema);
module.exports = Votes;
the console log counts out each i in the array so why the save function isn't being fired is stumping me
Thanks in advance
You need to use an async function to do an async for loop, there are many answer on here for that code. I would suggest a control flow library like async or if using a new version of node, use native promises instead. Promises all method is the best way to achieve this.

Using mongoose and Q.spread gives array callback parameters

I have the code below:
var mongoose = require('mongoose');
var Q = require("q")
mongoose.connect("mongodb://localhost/testdb");
var Schema = mongoose.Schema;
var employeeSchema = new Schema({
name:String
})
var Employee = mongoose.model('Employee', employeeSchema);
var departmentSchema = new Schema({
name:String
})
var Department = mongoose.model('Department', departmentSchema);
var employee = new Employee();
employee.name = "T.Smith";
var dept = new Department();
dept.name = "Sales";
Q.spread([
Q.nfcall(employee.save.bind(employee)),
Q.nfcall(dept.save.bind(dept))
],function(emp,dept){
console.log(JSON.stringify(emp));
console.log(JSON.stringify(dept));
mongoose.disconnect();
})
The log statements will yield the results below:
[{"__v":0,"name":"T.Smith","_id":"5358f3c53cd354bc70fe619f"},1]
[{"__v":0,"name":"Sales","_id":"5358f3c53cd354bc70fe61a0"},1]
Why are the results an array instead of a single object?
I get the same if i replace the last block of code with this block:
Q.all([
Q.nfcall(employee.save.bind(employee)),
Q.nfcall(dept.save.bind(dept))
]).spread(function(emp,dept){
console.log(JSON.stringify(emp));
console.log(JSON.stringify(dept));
mongoose.disconnect();
})
By the way, which block is recommended?
The save callback signature is function(err, result, numberAffected) which doesn't conform to node callback convention. nfcall expects a node callback signature, which is function(err, result). To avoid loss of information, the promise returned by nfcall resolves to [result, numberAffected].
Using .bind and Q.nfcall at call sites is very ugly anyway, so you can create a method that does all this:
mongoose.Model.prototype.saveForResult = function() {
return Q.nbind(this.save, this)().spread(function(result, numberAffected) {
return result;
});
};
Then:
Q.spread([
employee.saveForResult(),
dept.saveForResult()
],function(emp,dept){
console.log(JSON.stringify(emp));
console.log(JSON.stringify(dept));
mongoose.disconnect();
})

Resources