Node.js - Counting the number of objects in MongoDB collection - javascript

I am new to Node.js and MongoDB and I am really struggling to wrap my head around callbacks. I have read a few articles but it is still quite confusing to me. In the code below, I am trying to return the count of orders that have some properties which I have expressed in the query in orderModel.count(query, next):
controllers/order.js:
var mongoose = require ('../config/db');
var orderModel = require('../models/order').model;
var User = require('./user');
var Error = require('../config/error');
createOrder: function (user, order, next) {
if (newOrder.totalPrice > user.credit && orderModel.
count({$and: [{user: order.user}, {active: true}, {$or: [{status: 0}, {status: 1}]}]},
function(err, count){
if(err)
console.log(err);
else
count; }) > 0)
return next({error: Error.InsufficientCredits});
}
I don't think I am correctly obtaining the variable count because when I tried printing out the result of the second condition in the if statement, I got this data printed out:
Query {
_mongooseOptions: {},
mongooseCollection:
NativeCollection {
collection: Collection { s: [Object] },
opts: { bufferCommands: true, capped: false },
name: 'orders',
collectionName: 'orders',
conn:
NativeConnection {
base: [Object],
collections: [Object],
models: [Object],
config: [Object],
replica: false,
hosts: null,
host: 'dsXXXXXX.mlab.com',
port: XXXXXX,
user: 'XXXX',
pass: 'XXXX',
name: 'X',
options: [Object],
otherDbs: [],
_readyState: 1,
_closeCalled: false,
_hasOpened: true,
_listening: false,
db: [Object],
_events: {},
_eventsCount: 0 },
queue: [],
buffer: false,
emitter:
EventEmitter {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined } },
....

You need to put your logic inside the Model.count() method callback function as:
var mongoose = require ('../config/db'),
orderModel = require('../models/order').model,
User = require('./user'),
Error = require('../config/error');
var createOrder = function (user, order, next) {
orderModel.count({
"user": order.user,
"active": true,
"status": { "$in": [0, 1] }
}, function(err, count) { //<-- put logic in this callback
if (err) {
console.log(err);
throw err;
} else if (newOrder.totalPrice > user.credit && count > 0) {
// logic for creating order here
} else {
return next({ "error": Error.InsufficientCredits });
}
})
}

Related

Sequelize .set error, .set is not a function

I am trying to set up a belongsTo and hasMany association which seems to be working, but when I run .set I am getting the error fighterData.setUsers is not a function. The dialect is mySql. Here is my code:
Fighters.belongsTo(Users)
Users.hasMany(Fighters);
Users.sync()
Fighters.sync()
//creates the table if it doesn't exist
const insertFighter = function(obj, sessId) {
return Fighters.create(obj, {returning: true}).then((fighterData) => {
//console.log('inserted a fighter \n', fighterData);
return Users.findOne({
where: {
id: sessId
}
}).then((userData) => {
//console.log('fighterData in findOne promise \n', fighterData)
return fighterData.setUsers(userData)
}).then((success)=> {
console.log('user fighter join success')
return
}).catch((err)=> {
console.log('user fighter join error \n', err)
return
})
}).catch((err)=> {
console.log('error inserting fighter \n', err);
})
}
The error that's logging is user fighter join error.
interestingly, userData.setFighters(fighterData) works successfully, but that is not what I need
EDIT
This is what fighterData is:
fighterData in findOne promise
Fighters {
dataValues:
{ id: 7,
name: 'Gilbert Burns',
image:
'https://www.sherdog.com/image_crop/200/300/_images/fighter/20140806063215_IMG_8432.JPG',
next_opponent: 'Kamaru Usman',
next_fight: 'July 11, 2020 ',
style: 'mma',
updatedAt: 2020-06-17T06:00:40.368Z,
createdAt: 2020-06-17T06:00:40.368Z },
_previousDataValues:
{ name: 'Gilbert Burns',
image:
'https://www.sherdog.com/image_crop/200/300/_images/fighter/20140806063215_IMG_8432.JPG',
next_opponent: 'Kamaru Usman',
next_fight: 'July 11, 2020 ',
style: 'mma',
id: 7,
createdAt: 2020-06-17T06:00:40.368Z,
updatedAt: 2020-06-17T06:00:40.368Z,
UserId: undefined },
_changed:
{ name: false,
image: false,
next_opponent: false,
next_fight: false,
style: false,
id: false,
createdAt: false,
updatedAt: false,
UserId: false },
_modelOptions:
{ timestamps: true,
validate: {},
freezeTableName: false,
underscored: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: null,
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: {},
indexes: [],
name: { plural: 'Fighters', singular: 'Fighter' },
omitNull: false,
sequelize:
Sequelize {
options: [Object],
config: [Object],
dialect: [MysqlDialect],
queryInterface: [QueryInterface],
models: [Object],
modelManager: [ModelManager],
connectionManager: [ConnectionManager],
importCache: {} },
hooks: {} },
_options:
{ isNewRecord: true,
_schema: null,
_schemaDelimiter: '',
attributes: undefined,
include: undefined,
raw: undefined,
silent: undefined },
isNewRecord: false }
This is returned from entering one fighter's information into the database.
The problem is with the naming of your models.
Sequelize expects your models to be named in singular form (User instead of Users), so it's getting confused with what it should name the generated setter and getter methods for your association.
If you try fighterData.setUser(userData) instead of fighterData.setUsers(userData), it should work.
If you you want to use setUsers instead, you will have to make adjustments to your model to tell Sequelize to use Users as the singular form of User:
Users.init({
sessId: Sequelize.STRING
}, {
sequelize: sequelize,
name: {
singular: 'users'
}
});
You can overwrite the plural form the same way as well.
You can read more about this here: Sequelize naming strategy

How do I pass values from a Promise.all to .then()?

I have a promise chain that first collects contact objects and then processes the collected contacts. How can I pass the contacts to the .then() section after Promise.all()?
let collectUserDataPromise = []
allUsers.forEach((userId) => {
//Collect all contacts
collectUserDataPromise.push(
dbRoot.child(`users/${userId}`)
.once('value', (userSnapshot)=>{
const userNodeData = userSnapshot.val()
const contactObject = {
alias: (userNodeData.alias) ? userNodeData.alias : '',
name: (userNodeData.name) ? userNodeData.name : '',
status: 'active'
}
console.log('contactObject', contactObject)
//return contactObject
return new Promise((resolve, reject)=> resolve([contactObject]))
})
)
})
Promise.all(collectUserDataPromise)
.then((contactObjects)=>{
console.log('contactObjects', contactObjects)
My log shows that I have collected the objects correctly but that I cannot seem to pass then to the .then() section on last row in my code example.
Log from the .once() section
"contactObject { alias: 'Donald', name: 'Donald D', status: 'active'}"
"contactObject { alias: 'Mickey', name: 'Mickey M', status: 'active' }"
Log from the .then() section
"contactObjects [ DataSnapshot {
node_:
ChildrenNode {
children_: [Object],
priorityNode_: [Object],
indexMap_: [Object],
lazyHash_: null },
ref_:
Reference {
repo: [Object],
path: [Object],
queryParams_: [Object],
orderByCalled_: false },
index_: PriorityIndex {} },
DataSnapshot {
node_:
ChildrenNode {
children_: [Object],
priorityNode_: [Object],
indexMap_: [Object],
lazyHash_: null },
ref_:
Reference {
repo: [Object],
path: [Object],
queryParams_: [Object],
orderByCalled_: false },
index_: PriorityIndex {} },
DataSnapshot {
node_:
ChildrenNode {
children_: [Object],
priorityNode_: [Object],
indexMap_: [Object],
lazyHash_: null },
ref_:
Reference {
repo: [Object],
path: [Object],
queryParams_: [Object],
orderByCalled_: false },
index_: PriorityIndex {} } ]"
timestamp: "2019-09-08T18:50:40.259Z"
trace: "projects/xxxx/xxx"
}"
How can I pass all the collected values from Promise.all() to the .then() section of the promise chain?
It looks like the dbRoot.child('...').once('...') portion of your code is essentially the Promise you want to store in the collectUserDataPromise array. This means you shouldn't need to create your own Promise as you have done (return new Promise etc).
Try the following and let me know it that helps:
let collectUserDataPromise = [];
allUsers.forEach(userId => {
//Collect all contacts
collectUserDataPromise.push(
dbRoot
.child(`users/${userId}`)
.once("value")
.then(userSnapshot => {
const userNodeData = userSnapshot.val();
const contactObject = {
alias: userNodeData.alias ? userNodeData.alias : "",
name: userNodeData.name ? userNodeData.name : "",
status: "active"
};
//return contactObject
return contactObject;
})
);
});
Promise.all(collectUserDataPromise).then(contactObjects => {
console.log("contactObjects", contactObjects);
});

parse array of json with node.js

I'm new to node.js so apologies if this is something very simple.
I have the below node js script:
var http = require("http");
var bodyParser = require("body-parser");
var options = {
"method" : "GET",
"hostname" : "xxx.xxx.xxx.xxx",
"port" : "18080",
"path" : "/api/v1/applications/app-20180103124606-0007/stages/0"
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = JSON.parse(Buffer.concat(chunks));
console.log(body);
});
});
req.end();
It returns this JSON:
[ { status: 'COMPLETE',
stageId: 0,
attemptId: 0,
numActiveTasks: 0,
numCompleteTasks: 1,
numFailedTasks: 0,
executorRunTime: 2738,
executorCpuTime: 1207164005,
submissionTime: '2018-01-03T12:46:10.796GMT',
firstTaskLaunchedTime: '2018-01-03T12:46:10.810GMT',
completionTime: '2018-01-03T12:46:14.513GMT',
inputBytes: 0,
inputRecords: 99171,
outputBytes: 0,
outputRecords: 0,
shuffleReadBytes: 0,
shuffleReadRecords: 0,
shuffleWriteBytes: 1468516,
shuffleWriteRecords: 3872,
memoryBytesSpilled: 0,
diskBytesSpilled: 0,
name: 'reduceByKey at /scripts/wordcount.py:37',
details: 'org.apache.spark.rdd.RDD.<init>(RDD.scala:104)\norg.apache.spark.api.python.PairwiseRDD.<init>(PythonRDD.scala:391)\nsun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)\nsun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)\nsun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)\njava.lang.reflect.Constructor.newInstance(Constructor.java:423)\npy4j.reflection.MethodInvoker.invoke(MethodInvoker.java:247)\npy4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)\npy4j.Gateway.invoke(Gateway.java:236)\npy4j.commands.ConstructorCommand.invokeConstructor(ConstructorCommand.java:80)\npy4j.commands.ConstructorCommand.execute(ConstructorCommand.java:69)\npy4j.GatewayConnection.run(GatewayConnection.java:214)\njava.lang.Thread.run(Thread.java:748)',
schedulingPool: 'default',
accumulatorUpdates:
[ [Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object],
[Object] ],
tasks: { '0': [Object] },
executorSummary: { '0': [Object] } } ]
I now need to extract launchTime and taskTime. How is this done? I had previousy managed to extract data from JSON but I think I'm having trouble here as it's contained in an array.
You can use Array.prototype.forEach() to iterate over each member of the response body.
res.on('end', () => {
let body = JSON.parse(Buffer.concat(chunks))
body.forEach(item => {
// Do something with item
console.log(item)
})
})
If the array length is always 1, then you can access the first array element with body[0].
body[0].executorRunTime
body[0].firstTaskLaunchedTime
Otherwise you could iterate over the result with body.forEach().

Why does returning snapshot.val() in a Promise when using Promise.all not work?

I'm writing a Firebase Cloud Function and I'm trying to figure out how Promise.all works. In my code, I pass in an array of database queries and I'm trying the read the resulting array, but I'm only getting garbage:
T {
A:
P {
k: Sb { Ka: [Function: vb], ba: [Object] },
aa: P { k: [Object], aa: null, wb: [Object], Bb: '' },
wb: Zc { ld: [Object], ac: [Object] },
Bb: null },
V:
R {
u:
Gd {
app: [Object],
L: [Object],
Ua: [Object],
Sc: null,
ca: [Object],
td: 1,
Qa: [Object],
va: [Object],
qg: [Object],
jc: [Object],
ee: [Object],
md: [Object],
ia: [Object],
Xa: [Object],
cd: 2,
fe: null,
K: [Object] },
path: J { o: [Object], Y: 0 },
m:
Df {
xa: false,
ka: false,
Ib: false,
na: false,
Pb: false,
oa: 0,
kb: '',
bc: null,
xb: '',
Zb: null,
vb: '',
g: Tc {} },
Kc: false,
then: undefined,
catch: undefined },
g: Tc {} }
I'm expecting a simple json:
{
"name": "Foo",
"number": 2521
// And a few other fields
}
BTW, I watched Jen's video so I know what I'm doing is wrong anyway; I just want to know why my existing code doesn't work. (I haven't tested it, but I believe the solution is to return the raw snapshots in my db query and then do the .val() call.)
Relevant code if the links disappear:
function mergeTeams(duplicates) {
return Promise.all([
admin.database().ref(someRef).once('value', (snap) => {
return snap.val();
}),
admin.database().ref(someRef2).once('value', (snap) => {
return snap.val();
})
]).then(values => {
console.log(values);
const team1 = values[0];
const team2 = values[1];
console.log(team1);
console.log(team2);
}
So, here's the code that works (and the explanation below):
return Promise.all([
admin.database().ref(teamRef + duplicates.teamKey1).once('value'),
admin.database().ref(teamRef + duplicates.teamKey2).once('value')
]).then(values => {
const team1 = values[0].val();
const team2 = values[1].val();
console.log(team1);
console.log(team2);
});
The reason it works is because I've always getting the promises in the values array even though I didn't know it. Here's what Promise.all returns: an array with the raw result of the promises passed in. When I was returning stuff inside the success callback, that didn't actually do anything because it wasn't part of the promise; I was just returning random stuff to an empty void. And when I was printing the teams, I was actually logging the Firebase Snapshot object instead of the .val().

Can't retrieve data from mongoDB with Node.js

I'm pretty new in Node.js and I have this project. Basically I have some data sits in a mongoDB collection("data") and I'm trying to get that data and display it on the browser.
Here is what I've got so far;
var MongoClient = require('mongodb').MongoClient
,format = require('util').format;
var sys = require ("sys");
my_http = require("http");
my_http.createServer(function(request, response){
sys.puts("Touched !!");
response.writeHeader(200, {"Content-Type": "text/plain"});
response.write(extractData()).toString();
response.end();
}).listen(8080);
sys.puts("Server is running on 8080"); // Server kicks in...np
function extractData(){
MongoClient.connect('mongodb://127.0.0.1:27017/mongoDB', function(err, db){
if (err){
console.log("Can't Connect to DB !!");
}else {
console.log("Connected to DB !!"); // connects to DB, np
db.data.find({}, function(err, data){ // .find is the problem
if (err || !data) console.log("No Data Found");
else data.forEach(function (data){
console.log(data);
});
}).toArray();
}
});
}
And after I run "node server.js" and refresh the already open localhost:8080, I get this;
Server is running on 8080
Touched !!
Touched !!
Connected to DB !!
d:\Projects\SCRIPTS\mdp.scripts.testing-tools\jsFinderWmongoDB\node_modules\mongodb\lib\mongodb\mongo_client.js:475
throw err
^
TypeError: Cannot call method 'find' of undefined
at d:\Projects\SCRIPTS\mdp.scripts.testing-tools\jsFinderWmongoDB\server.js:21:21
at d:\Projects\SCRIPTS\mdp.scripts.testing-tools\jsFinderWmongoDB\node_modules\mongodb\lib\mongodb\mongo_client.js:4
72:11
at process._tickCallback (node.js:415:13)
Don't understand why there is a problem with .find() and of course can't display any data...
Any ideas?
Edit:
Well, we are certainly getting somewhere. I've made some changes.
Current code:
function extractData(){
MongoClient.connect('mongodb://127.0.0.1:27017/mongoDB', function(err, db){
if (err){
console.log("Can't Connect to DB !!");
}else {
sys.puts("Connected to DB !!"); // connects to DB, np
db.collection('data').find({}, function(err, data){
if (err || !data) console.log("No Data Found");
//else db.collection('data').forEach(function (data){
// console.log(data);
//});
});//.toArray();
}
});
}
Browser response is "undefined"
I'm guessing "extractData" function is NOT returning something legit. Therefore the collection set "data" is returning empty.
And yes I've checked one more time, I have data in the dataset.
You need to set a collection to use before you can do anything with it.
var collection = db.collection('data');
collection.find({},function(err,data){
console.log(data);
});
Would be how you do it.
Update ** This was how I did my first mongoDB stuff using express
Might help you.
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/nodetest1');
app.get('/userlist', function(req, res) {
var db = req.db;
var collection = db.get('usercollection');
collection.find({},{},function(e,docs){
res.render('userlist', {
"userlist" : docs
});
});
});
I get the details about the stored data when do console.log(data);
Here is a glimpse of it
Server is running on 8080
Touched !!
Connected to DB !!
{ db:
{ domain: null,
_events: {},
_maxListeners: 10,
databaseName: 'mongoDB',
serverConfig:
{ domain: null,
_events: {},
_maxListeners: 10,
auth: [Getter],
_callBackStore: [Object],
_commandsStore: [Object],
_dbStore: [Object],
host: '127.0.0.1',
port: 27017,
options: [Object],
internalMaster: true,
connected: true,
poolSize: 5,
disableDriverBSONSizeCheck: false,
_used: true,
replicasetInstance: null,
emitOpen: false,
ssl: false,
sslValidate: false,
sslCA: null,
sslCert: undefined,
sslKey: undefined,
sslPass: undefined,
serverCapabilities: [Object],
name: '127.0.0.1:27017',
socketOptions: [Object],
logger: [Object],
eventHandlers: [Object],
_serverState: 'connected',
_state: [Object],
recordQueryStats: false,
socketTimeoutMS: [Getter/Setter],
_readPreference: [Object],
db: [Circular],
dbInstances: [Object],
connectionPool: [Object],
isMasterDoc: [Object] },
options:
{ read_preference_tags: null,
read_preference: 'primary',
url: 'mongodb://127.0.0.1:27017/mongoDB',
native_parser: true,
readPreference: [Object],
safe: false,
w: 1 },
_applicationClosed: false,
slaveOk: false,
bufferMaxEntries: -1,
native_parser: true,
bsonLib:
{ BSON: [Object],
Long: [Object],
ObjectID: [Object],
DBRef: [Object],
Code: [Object],
Timestamp: [Object],
Binary: [Object],
Double: [Object],
MaxKey: [Object],
MinKey: [Object],
Symbol: [Object] },
bson: { promoteLongs: true },
bson_deserializer:
{ Code: [Object],
Symbol: [Object],
BSON: [Object],
DBRef: [Object],
Binary: [Object],
ObjectID: [Object],
Long: [Object],
Timestamp: [Object],
Double: [Object],
MinKey: [Object],
MaxKey: [Object],
promoteLongs: true },
bson_serializer:
{ Code: [Object],
Symbol: [Object],
BSON: [Object],
DBRef: [Object],
Binary: [Object],
ObjectID: [Object],
Long: [Object],
Timestamp: [Object],
Double: [Object],
MinKey: [Object],
MaxKey: [Object],
promoteLongs: true },
_state: 'connected',
pkFactory:
{ [Function: ObjectID]
index: 16043018,
createPk: [Function: createPk],
createFromTime: [Function: createFromTime],
createFromHexString: [Function: createFromHexString],
isValid: [Function: isValid],
ObjectID: [Circular],
ObjectId: [Circular] },
forceServerObjectId: false,
safe: false,
notReplied: {},
isInitializing: true,
openCalled: true,
commands: [],
logger: { error: [Function], log: [Function], debug: [Function] },
tag: 1425061857066,
eventHandlers:
{ error: [],
parseError: [],
poolReady: [],
message: [],
close: [] },
serializeFunctions: false,
raw: false,
recordQueryStats: false,
retryMiliSeconds: 1000,
numberOfRetries: 60,
readPreference: { _type: 'ReadPreference', mode: 'primary', tags: undefined } },
collection:

Categories