`find()` Not Working Like `findOne()` After Connecting to MongoDB Via Node - node.js

I am familiar with how to get documents from the Mongo shell, but am having difficulty getting documents using find() when connecting via Node.
What I'm getting right now looks like a lot of cursor info, but not the actual documents.
What do I need to change with the following code so that I get the actual documents logged to the console for 'results'?
const config = require('./../../../configuration');
const url = config.get('MONGO_URL');
const dbName = config.get('MONGO_DATABASE');
const MongoClient = require('mongodb').MongoClient;
const client = new MongoClient(url);
module.exports = async function getSchedules() {
let results;
return new Promise((resolve, reject) => {
client.connect(async function (err) {
if (err) return reject(err);
try {
const db = await client.db(dbName);
results = await db.collection('schedules').find();
} catch (error) {
return reject(error);
}
return resolve(results);
});
});
};
... And here's where I actually try and get the documents:
async function getSchedulesFromDB() {
await getSchedules().then((schedules => {
console.log('schedules: ', schedules); // expect result here
return schedules;
}));
}
When I used this same kind of code structure on a findOne(), it worked. But here when using a find() it is not. What am I missing? Does find() work fundamentally differently than findOne()?

Yes. find() returns a cursor over which you must iterate. findOne() returns a single doc, not a cursor. If you want an array of results, you must "build it yourself" by iterating the cursor, something like:
results = [];
db.collection('schedules').find().forEach(function(d) { results.push(d); });

Related

Function that return undefined in node.js. Inside the function I have mongoDB.connect

I tried to make function for my project in the service. This service need to check is user exists in my database, but my function(this function is checking) inside the class return undefined.
This is my code:
const express = require("express");
const mongoDB = require('mongodb').MongoClient;
const url = "here I paste url to my databse(everything is good here)";
class CheckService {
isUserExists(username) {
mongoDB.connect(url, (error, connection) => {
if (error) {
console.log("Error", '\n', error);
throw error;
}
const query = {name: username};
const db = connection.db("users");
const result = db.collection("users").find(query).toArray(
function findUser(error, result) {
if (error) {
throw error;
}
const arr = [];
if (result.value === arr.value) {
console.log(false);
connection.close();
return false;
} else {
console.log(true);
console.log(arr);
console.log(result);
connection.close();
return true;
}
});
console.log(result);
});
}
}
module.exports = new CheckService();
I imported my service to another service:
const checkService = require('./check.service');
After this, I invoked my function from my service like this:
console.log('function:',checkService.isUserExists(username));
I expected good result, but function doesn't return, that I want, unfortunately.
Please help!
There are two problems with your function
it doesn't return anything
toArray() is a promise, so your console.log probably just prints a promise.
Probably you're looking for something like this:
class CheckService {
async isUserExists(username) {
const connection = await mongoDB.connect(url);
const query = {name: username};
const db = connection.db("users");
const result = await db.collection("users").find(query).toArray();
connection.close();
return result.length !== 0;
}
}
You'd then invoke it with something like
await new CheckService().isUserExists(username);
Though, it's worth noting that you probably don't need toArray and instead could use findOne or even count() since all you care about is existence. I probably also wouldn't instantiate a new connection each time (but that's not super relevant)
2 things wrong here. Firstly the first comment is correct. You're only logging the result and not passing back to the caller. Secondly, a quick peek at the mongo docs shows that retrieval methods are promises. You need to make the function async and add awaits where needed.
Mongo:
https://www.mongodb.com/docs/drivers/node/current/fundamentals/crud/read-operations/retrieve/
Promises:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

await doesn't wait for function to end

I know this has been asked a lot but I can't seem to use the existing answers to get my code to work. I am trying to use mongojs to make a single query, then put the results in a global (relative to the scope) variable to avoid nesting multiple callbacks. However, I can't seem to get the code to wait for the query to end before continuing.
async function taskmaster() {
const db = mongojs(mongoUri.tasker);
let currentDoc;
const getTask = async function() {
db.tasks.findOne({'task_id': {'$in': [taskId, null]}}, function(err, doc) {
console.log(doc);
currentDoc = doc;
});
}
await getTask();
console.log(currentDoc);
// Code to process currentDoc below
}
No matter what I do, console.log(doc) shows a valid MongoDB document, yet console.log(currentDoc) shows "undefined". Thanks in advance!
Inside your async function, you use findOne method() in callback style, so it's totally normal that console.log(currentDoc) shows undefined, because it executes before
currentDoc = doc;
You can promisify the findOne method, to use it with async/await keyword.
I found a tutorial to promisfy a callback style function here, hope it help : https://flaviocopes.com/node-promisify/
--- EDIT ---
I rewrite your code when promising the findOne method, as suggested by O.Jones
async function taskmaster() {
const getTask = async (taskId) => {
return new Promise((resolve, reject) => {
db.tasks.findOne({'task_id': {'$in': [taskId, null]}}, function(err, doc) {
if(err) {
console.log("problem when retrieve data");
reject(err);
} else {
resolve(doc);
}
});
})
const db = mongojs(mongoUri.tasker);
const currentDoc = await getTask(taskId);
console.log(currentDoc);
}

Retrieving values from database using node and mssql

Here's a simple script i made:
const Nightmare = require('nightmare');
const sql = require('mssql');
const itens = getRecords();
async function getRecords(){
let itensList = [];
const cfg = {
//config here
};
sql.connect(cfg, function(err){
if(err) console.log(err);
let request = new sql.Request();
request.query("<query here>", (err, result) => {
if(err) console.log(err);
itensList = result;
});
return itensList;
});
}
async function getPrices(){
try{
console.log(itens)
}catch(e){
console.log(e);
}
}
getPrices();
Everything works, but when the getPrices() function gets called, here's what's being logged:
Promise { undefined }
What am i missing here?
request.query is being called, but itenslist is being returned before it can be assigned.
Basically, the order of what is happening is:
request.query is called, and starts running the query.
Since request.query is asynchronous, we move on to the next task - returning itenlist
request.query finishes running, and assigns itenlist the expected value after it has already been returned.
To get your desired functionality, I would recommend using callbacks (which node-mssql supports). Alternatively, you could use the await keyword. For instance:
var queryText = 'SELECT 1 AS Value';
var queryResults = await connection.query(queryText);

How to write a static method in Mongoose that gets all documents?

I'm new to Mongoose. I wrote a statics method and a instance method for a Mongoose schema named 'questionSchema' and exported it like so:
var questionSchema = new Schema({
...
})
questionSchema.methods.createQuestion = function(){
return this.save(function(err){
if(err){
return err
};
return 'Saved the question';
});
};
questionSchema.statics.getAllQ = function(){
return this.find({}, function(err, res){
if(err){
return err
};
return res;
});
}
module.exports = mongoose.model('Question', questionSchema)
Then in a route in my Node/Express server, I imported the it as a model, and tried calling the static method, which should return all the documents under the Question model:
const Question = require('../models/question.js');
...
router.post('/qcrud/submit', (req, res) => {
let reqBody = req.body;
var newQuestion = new Question({reqBody});
newQuestion.createQuestion();
})
router.get('/qcrud/getAll',(req, res) => {
let qArr = Question.getAllQ()
res.send(qArr);
});
However, it returns a Query object, not an array like I expected. I looked around and saw on MDN that
'If you don't specify a callback then the API will return a variable
of type Query.'
I did specify a callback, but still got the Query object. First of all, am I using my static and instance methods right? Are the documents even saving? And how do I access the array documents saved?
If you're using Node 8.x you can utilize async/await
This way your code will look more synchronous:
questionSchema.statics.getAllQ = async () => {
return await this.find({});
}
router.get('/qcrud/getAll',async (req, res) => {
let qArr = await Question.getAllQ();
res.send(qArr);
});
You can find a really nice article that is explaining how to use Mongoose with async/await here.

Mock ArangoJS on NodeJS unit test

I am using ArangoDB as storage of my sample JSON license file. I have a function that contains an AQL query like this:
listLicenses: async function listLicenses() {
let result = [];
await this.useLicenseDb();
const licenseCol = await db.collection('licenseCollection');
try {
const query = {
query: "FOR doc in licenseCollection RETURN {licenseId: doc.licenseId, licenseName: doc.licenseName, clientName: doc.clientName, useCase: doc.useCase, expirationDate: doc.expirationDate, callType: doc.callType}"
};
const cursor = await db.query(query);
result = await cursor.all();
} catch (err) {
console.error(err);
return err;
}
return result;
}
This function is querying any document present in licenseCollection collection inside an ArangoDB.
What I need is to create a unit test that calls/mocks this function, without using/needing ArangoDB Client/Server. Anyone has done like this or similar to this?
Thank you!

Resources