Using mongoose and Q.spread gives array callback parameters - node.js

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();
})

Related

MongoDb query by _id using Node

const cCurser = await client
.db("Database")
.collection("Collection")
.findOne({
_id: ObjectId(Filter)
}).then(function(item){
Obj = item;}
);
I'm trying to query the MongoDB by the _id but it returns Promise { }. please help me to retrieve the data in it.
Error detected:ReferenceError: ObjectId is not defined
add this before your query:
import mongoose from 'mongoose';
const { ObjectId } = mongoose.Types;
OR:
use this:
const cCurser = await client
.db("Database")
.collection("Collection")
.findOne({
_id: new mongoose.Types.ObjectId(Filter)
}).then(function(item){
Obj = item;}
);
Firstly, don't mix await syntax with the then syntax.
Either use await
let Obj = null;
const cCurser = await client
.db("Database")
.collection("Collection")
.findOne({
_id: ObjectId(Filter)
});
//Use Obj
Or the then syntax. Here you will have to write the rest of the code dependent on Obj inside then().
let Obj = null;
const cCurser = client
.db("Database")
.collection("Collection")
.findOne({
_id: ObjectId(Filter)
}).then(function(item){
Obj = item;
//Use Obj
}
);
Also based on your edit,it seems you have not imported ObjectId method from Mongo.
let mongo = require('mongodb');
let ObjectId = mongo .ObjectID
```

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

Hook to a specific Mongoose model query

I have self contained model in invoice.js
'use strict';
// load the things we need
var mongoose = require('mongoose');
var auth_filter = require('../../auth/acl/lib/queryhook');
var invoice_db = mongoose.createConnection(config.mongo.url + '/invoiceDB');
// PROMISE LIBRARY USED FOR ASYNC FLOW
var promise = require("bluebird");
var Schema = mongoose.Schema, ObjectId = Schema.Types.ObjectId;
// define the schema for our invoice details model
var invoicedetailSchema = new Schema({
//SCHEMA INFO
});
var InvoiceModel = invoice_db.model('InvoiceDetail', invoicedetailSchema);
// create the model for seller and expose it to our app
auth_filter.registerHooks(InvoiceModel);
module.exports = InvoiceModel;
I want to hook to the pre query for this model. I am trying to accomplish that using hooks but i am not successful with that. I am registering the hook using auth_filter file as below
'use strict';
var hooks = require('hooks'),
_ = require('lodash');
exports.registerHooks = function (model) {
model.pre('find', function(next,query) {
console.log('test find');
next();
});
model.pre('query', function(next,query) {
console.log('test query');
next();
});
};
What am I doing wrong? I want to keep the hooks separate so that I can call for a lot of different models.
Query hooks need to be defined on the schema, not the model. Also, there is no 'query' hook, and the query object is passed to the hook callback as this instead of as a parameter.
So change registerHooks to be:
exports.registerHooks = function (schema) {
schema.pre('find', function(next) {
var query = this;
console.log('test find');
next();
});
};
And then call it with the schema before creating your model:
var invoicedetailSchema = new Schema({
//SCHEMA INFO
});
auth_filter.registerHooks(invoicedetailSchema);
var InvoiceModel = invoice_db.model('InvoiceDetail', invoicedetailSchema);

mongoose insert data with promise

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();
})
})
}

Express, Mongoose : OverwriteModelError : Cannot Overwrite 'xxxxx' model once compiled

I'm encoutering an error when using a Mongoose Model in my program.
I've did that in the beginning of my code :
var Schema = mongoose.Schema;
mongoose.connect('xxxxx');
I used a first schema called userSchema to connect/sign up a user.
I've this code, which should do a random on the field Bonus of my DB. But when I go to the randTest page, I have this error. How can I fix it ?
app.get('/randTest', function(req,res)
{
var bonusSchema = new Schema({
bonus : [String]
});
var bonusModel = mongoose.model('Plateau', bonusSchema);
var query = bonusModel.find(null);
query.exec(function (err, allBonus){
if(err) { throw err;}
var rand = Math.floor((Math.random() *allBonus.length));
var result = allBonus[rand-1];
});
res.render('randTest', {result: result});
});
In my Jade file I've just :
extends layout
block content
script.
alert({#result});
Move the bonusModel definition outside of app.get so that it's only called once:
var bonusSchema = new Schema({
bonus : [String]
});
var bonusModel = mongoose.model('Plateau', bonusSchema);
app.get('/randTest', function(req,res)
{
var query = bonusModel.find(null);
...
});

Resources