I created some functions containing MongoDB methods in one File. It works well when I access the function from the same file, but when I am trying to access the function from another file, it doesn't work.
Here is the code
const Chain = require('../database/models/chains')
const getlatestChain = async () => {
try {
const thechains = await Chain.countDocuments()
if (thechains < 2) {
throw new Error('there is only one chain!')
}
return thechains
} catch (error) {
return error
}
}
module.exports = {
getlatestChain: getlatestChain
}
It doesn't work when I call it from another file
const thechain = require('../src/utils/chain')
require('../src/database/database')
thechain.getlatestChain()
.then((result) => {
console.log('how many documents : ' + result)
}).catch((err) => {
console.log(err)
});
error
TypeError: Chain.countDocuments is not a function
check the chains model to make sure you are exporting the countDocuments function, check the spelling as well if it is exported
Related
Recently I start using MongoDB with Mongoose on Nodejs.
This code works as it should, and returns me all data i need :
const getAllPosts = async () => {
try {
return (await PostModel.find().populate('user')).reverse();
} catch (error) {
console.log(error);
throw Error('Error while getting all posts');
}
};
But now I only need individual posts, which in the tags (represented as an array in the PostModel) contain the data that I will pass in the request.
For example, I will make a GET request to /posts/tag111 and should get all posts that have "tag111" in the tags array.
Any ways to do this?
If you are using expressjs, your route should be something like:
whatever.get('/:tag', postController.getAllPostTagged)
The function you use in your route (called getAllPostTagged above) should be similar to this one, in which you get the path param tag from req:
const postController = {
getAllPostTagged = async(req, res) => {
try {
return (await PostModel.find({tags: req.params.tag}));
} catch (error) {
console.log(error);
throw Error('Error while getting all posts');
}
}
}
The key here is to know where the params are obtained (from req.params) .
I am developing a server project which needs to call some functions synchronously. Currently I am calling it in asynchronous nature. I found some similar questions on StackOverflow and I can't understand how to apply those solutions to my code. Yet I tried using async/await and ended up with an error The 'await' operator can only be used in an 'async' function
Here is my implementation
function findSuitableRoom(_lecturer, _sessionDay, _sessionTime, _sessionDuration, _sessionType){
let assignedRoom = selectRoomByLevel(preferredRooms, lecturer.level, _sessionDuration); <------- Need to be call synchronously
if (!assignedRoom.success){
let rooms = getRooms(_sessionType); <------- Need to be call synchronously
assignedRoom = assignRoom(_lecturer.rooms, _sessionDuration, _lecturer.level);
} else {
arr_RemovedSessions.push(assignedRoom.removed)
}
return assignedRoom;
}
function getRooms(type){
switch (type){
case 'Tutorial' : type = 'Lecture hall'
break;
case 'Practical' : type = 'Lab'
break;
default : type = 'Lecture hall'
}
Rooms.find({type : type},
(err, rooms) => {
if (!err){
console.log('retrieved rooms ' + rooms)
return rooms;
}
})
}
Here I have provided only two methods because full implementation is very long and I feel if I could understand how to apply synchronous way to one method, I can manage the rest of the methods. Can someone please help me?
Well yes await is only available inside an async function so put async infront of findSuitableRoom.
Also you did a classic mistake. You use return inside of a callback function, and expect getRooms to return you some value.
async function findSuitableRoom(
_lecturer,
_sessionDay,
_sessionTime,
_sessionDuration,
_sessionType
) {
let assignedRoom = selectRoomByLevel(
preferredRooms,
lecturer.level,
_sessionDuration
);
if (!assignedRoom.success) {
try {
let rooms = await getRooms(_sessionType);
} catch (err) {
console.log("no rooms found");
}
assignedRoom = assignRoom(
_lecturer.rooms,
_sessionDuration,
_lecturer.level
);
} else {
arr_RemovedSessions.push(assignedRoom.removed);
}
return assignedRoom;
}
Also wrap it in an try / catch
Since .find() returns an promise if you dont pass an callback you can write it like this
function getRooms(type) {
switch (type) {
case "Tutorial":
type = "Lecture hall";
break;
case "Practical":
type = "Lab";
break;
default:
type = "Lecture hall";
}
return Rooms.find({ type });
}
Note here findSuitableRoom is no longer synchronouse. Its async and returns an promise. That means you will need to use the function like this:
findSuitableRoom.then(res => { console.log(res); })
The 'await' operator can only be used in an 'async' function
This means whenever you want to use the await keyword it needs to be inside a function which has an async keyword (returns promise)
read this https://javascript.info/async-await for more info
const add = (a, b) => {
return new Promise((resolve, reject) => {
setTimeout(() => { //to make it asynchronous
if (a < 0 || b < 0) {
return reject("don't need negative");
}
resolve(a + b);
}, 2000);
});
};
const jatin = async () => {
try{
const sum = await add(10, 5);
const sum2 = await add(sum, -100);
const sum3 = await add(sum2, 1000);
return sum3;
} catch (e) {
console.log(e);
}
};
jatin()
Try this
let's understand this
add is a normal function that does some asynchronous action like
waiting for 2 seconds
normally we use await with async function so in order to use it we make as async function jatin and use await with add function call
to make it synchronous, so until first await add call() doesn't
happen it wont execute another await add call().
Example code if you will use in your app.js
router.post("/users/login", async (req, res) => {
try {
const user = await User.findByCredentials(
req.body.email,
req.body.password
);
const token = await user.generateToken();
res.status(200).send({
user,
token,
});
}
catch (error) {
console.log(error);
res.status(400).send();
}
});
I'm creating a utilities class to handle some of our common functions to help reduce code copy/past in our modules: I created an exports module. All that's happening here is the export of an object which contains three functions.
module.exports = {
//retrieve a secret object from the AWS Secrets Manager
//Parameter should be string value of the Secret ID
getSecretIdAsync : async (param) => {
return await new Promise((resolve, reject) => {
scrtmgr.getSecretValue({SecretId: param}, (err, data) => {
if(err){
reject(console.log('Error getting SecretId: ' + err, err.stack));
} else{
if('SecretString' in data)
return resolve(JSON.parse(data.SecretString));
}
});
});
},
//retrieves the AWS Paramter value from the AWS Paramter store
//param should be string value of parameter hierarchical id
getParameterValueFromStoreAsync : async (param) => {
return await new Promise((resolve, reject) => {
servmgr.getParameter({ Name: param}, (err, data) => {
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
}
return resolve(data.Parameters.Value);
});
});
},
//retrieves the AWS Paramter "object" from the AWS Paramter store
//param should be string value of parameter hierarchical id
getParameterFromStoreAsync : async (param) => {
return await new Promise((resolve, reject) => {
servmgr.getParameter({ Name: param}, (err, data) => {
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
}
return resolve(data.Parameters);
});
});
}
}
Whenever I attempt to reference this module (say in my unit test I reference to module as:
let chai = require('chai');
let ut = require('../utilities.js');
let expect = chai.expect;
let aws = require('aws-sdk-mock');
describe('get parameter value', ()=>{
it('resolves', (done)=>{
var result = aws.mock('SSM', 'putParameter' , {"Name": "someName", "Value": "someValue"} );
console.log('###### ' + JSON.stringify(ut));
//console.log(obj);
});
});
directory structure is
utilities.js is located in the root, where the unit test is in a folder called test.
Whenever I try to import the utilities module the object it always empty.
console.log('###### ' + JSON.stringify(ut)); generates ###### {}
I've exported individual functions in the past and I thought a group of functions would just require exporting a constructor.
Should multiple functions be exported in a different manner?
MDN web docs offers an explanation for the behavior that you're seeing with JSON.strigify():
If undefined, a Function, or a Symbol is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
edit: To clarify, I think you're exporting your utility functions correctly, but JSON.stringify() explicitly promises to not print functions.
JSON.stringify doesn't serialize functions, if you need to do so you have to use a custom stringify function like this https://github.com/braceslab/json-stringify-extended
so, running
console.log(ut)
will print
{ getSecretIdAsync: [AsyncFunction: getSecretIdAsync],
getParameterValueFromStoreAsync: [AsyncFunction: getParameterValueFromStoreAsync],
getParameterFromStoreAsync: [AsyncFunction: getParameterFromStoreAsync] }
also, you can remove async and await from your functions, are useless using return new Promise
util.promisify appears to always expect 2 parameters from a callback function, however the existing functions do not have a seperate callback for err and data, but only a single callback.
How can I handle this ???
const {promisify} = require('util');
function y(text,cb){
setTimeout(function(){cb({error:false,data:text})},1000);
}
async function test(text) {
try{
const z = promisify(y)
return await z(text);
} catch(e) {return {error:true,msg:e}}
}
console.log(test('xxx'));
What I am looking for is to return the value from function y syncronously and not getting a promise i.e.
var x = test('xxx');
Given the information in your comment, you can wrap the function with a compatible signature to be passed directly to promisify():
const { promisify } = require('util')
function y (query, callback) {
callback(query)
}
function yCompatible (query, callback) {
y(query, ({ error, data }) => {
callback(error && data, error || data)
})
}
const yAsync = promisify(yCompatible)
async function test (query) {
try {
return yAsync(query)
} catch (error) {
return error
}
}
test('xxx').then(
data => { console.log(data) },
error => { console.error(error) }
)
Also try not to get in the habit of using single letter variables like a mathematician ;) I realize this is just example code, but even then it's helpful to be a bit more explicit about your intent.
I get a strange error and can't figure out what I am doing wrong. I wrote a graphql mutation to call an api:
domainStuff: async (parent, { command, params }, { models }) => {
console.log("Params:", params);
const result = await dd24Api(command, params);
return result;
}
This it the function I call:
export default async (command, parameter) => {
const args = _.merge({ params: parameter }, auth);
// Eleminate copying mistakes
console.log(typeof args);
const properCommand = command + "Async";
const result = await soap
.createClientAsync(apiWSDL)
.then(client => {
return client[properCommand](args)
.then(res => {
console.log(res[command + "Result"]);
return res[command + "Result"];
})
.catch(err => {
console.log(err);
return err;
});
})
.catch(err => console.log(err));
return result;
with this query variables:
{
"command": "CheckDomain",
"params": {"domain": "test.it"}
}
The console.log shows me that args is an object, but I get this error (from the first catch block):
TypeError: obj.hasOwnProperty is not a function
How can that be? After all I checked whether it is an object and it is. More strange, if I give a hardcoded object into the query, this for example:
domainStuff: async (parent, { command, params }, { models }) => {
console.log("Params:", params);
const result = await dd24Api(command, {domain: "test.com"});
return result;
}
then it works perfectly fine. What am I doing wrong? Thx for any help in advance.
EDIT: I am using "graphql-server-express": "^0.8.0" and "graphql-tools": "^1.0.0"
If you are using graphql-js there are a lot of places where new objects are created using Object.create(null) which is different from {} you can read an explanation about that here Creating Js object with Object.create(null)?
But essentially an object created with Object.create(null) has no hasOwnProperty method
You can try it in node with
const obj1 = Object.create(null)
console.log(typeof obj1.hasOwnProperty)
// 'undefined'
const obj2 = {}
console.log(typeof obj2.hasOwnProperty)
// 'function'
Another method you can use for determining if an object has a key that will work on an object created with Object.create(null) is
function hasKey(obj, key) {
return Object.keys(obj).indexOf(key) !== -1
}
You can convert it to a standard Object by:
data = JSON.parse(JSON.stringify(data));
Okay, after an extensive period of trial and error I was able to fix the problem. Changing the position of the objects I pass into the .merge function was the solution. The working code is:
const args = _.merge(auth, { params: parameter });
Both are objects, but it seems like the object coming from the graphql variables did not have the required hasOwnProperty method. Simply speaking, instead of copying the "good object" (auth) into the bad one (parameter), I copy the bad one into the good one which has the needed function.
Hopefully this helps someone else who also experiences this error.