I want to use mongodb with sails but without any ORM. So below is my service to connect mongodb.
Service:
//DbService.js
const MongoClient = require('mongodb').MongoClient;
module.exports = {
db:function(req, res){
var connect=MongoClient.connect("mongodb:***********").then(function (err, database) {
if(err) console.log(err);
else{
database=database.db('*****');
return connect;
}
});
}
}
After connection i have called it in controller, But getting TypeError: Cannot read property 'then' of undefined.
controller:
//HomeControlelr.js
module.exports = {
index:function(req, res){
DbService.db().then(function(err,db) {
console.log(db);
})
}
};
First npm i mongodb because you'll need to wrap any ID's with new ObjectID(idStr).
Then you can do this:
const collection = Pet.getDatastore().manager.collection(Pet.tableName);
const res = await collection.find({ name: { $regex: /blue/ } });
const dataWithObjectIds = await res.toArray();
const dataWithIds = JSON.parse(JSON.stringify(rawDataArr).replace(/"_id"/g, '"id"'));
I created a helper function to do all of this for us:
/**
* Use by chaining as if you were acting on a collection. So can use .find .aggregate etc.
* Returns json searializable data.
*
* #param {class} model A model
* #param {number} cnt - Number of chains on this, so I know when it reached the end
*/
function nativeMongoQuery(model, cnt) {
const collection = model.getDatastore().manager.collection(model.tableName);
let callCnt = 0;
let req;
const proxy = new Proxy({}, {
get: (_, method) => (...args) => {
if (!req) req = collection[method](...args);
else req = req[method](...args);
callCnt++;
if (callCnt === cnt) {
return (async function() {
const rawDataArr = await req.toArray();
return JSON.parse(JSON.stringify(rawDataArr).replace(/"_id"/g, '"id"'));
})();
} else {
return proxy;
}
}
});
return proxy;
}
module.exports = nativeMongoQuery;
I don't like the JSON parse and stringify and global replace. But if I don't do the stringify, then mongo _id's are all ObjectIds.
Use it like this:
const { ObjectId } = require('mongodb');
function makeObjectId(id) {
return new ObjectId(id);
}
const ownerIds = ['5349b4ddd2781d08c09890f4', '5349b4ddd2781d08c09890f5']
const ownerObjectIds = ownerIds.map(makeObjectId);
await nativeMongoQuery(Pet, 2).find({ owner: { $in: ownerObjectIds } }).sort({ dueAt: 1 });
Here is another example:
const mostRecentlyCreatedPets = await nativeMongoQuery(Pet, 1).aggregate([
{ $match: { owner: { $in: ownerObjectIds } } },
{ $sort: { createdAt: -1 } },
{ $limit: 1 }
]);
The cnt argument tells you how many things you have chained off of there.
As you can see in docs MongoClient.connect() doesn't return Promise object. Instead of this use callback function
module.exports = {
db:function(){
var connect = MongoClient.connect("mongodb:***********", function (err, database) {
//...
}
});
}
}
btw. Your call DbService.db function in controller will also fail, cuz your service function also doesn't return Promise
Before you go on, read something about Promises and callback functions
Related
I`m creating API on my express.js server, so when it takes "get" request, some function placed in module file asking data from graph db:
module.js file:
function getGraphData() {
const cityName = 'Milan';
const readQuery = `MATCH (City {name: $cityName})-[:LINKED*1..3]-(city:City) RETURN city`;
const cities = [];
session
.run(readQuery, { cityName })
.then(function (result) {
result.records.forEach(function (record) {
cities.push({
title: record._fields[0].properties.name,
});
});
return cities;
})
.catch((err) => console.log(err));
}
module.exports.getGraphData = getGraphData;
After receiving data it stores in array named cities and looks like this:
cities: [ { title: 'City1' }, { title: 'City2' }, { title: 'City3' } ]
So, function is returning this array, and then I import function from module and use it in my router file:
const { getGraphData } = require('./../db/neo4j');
router.get('/', async (req, res) => {
try {
const p = await getGraphData();
console.log('p:', p); //p is undefined
//return res.status(200).send(p);
return res.status(206).json(p); // empty response, not any data only status code
} catch (e) {
console.log(e);
});
So, what I'm doing wrong? Why does api response is empty?
Im use debugger. Data realy comes to function in module, but doesn`t passing to api response to "p" variable.
Your getGraphData function is using .then . When it executes it makes the session call and returns immediately that is why it returns empty.
Although, you are doing await on getGraphData, your getGraphData function needs to be defined as async and use await with session for it to work.
async function getGraphData() {
const cityName = 'Milan';
const readQuery = `MATCH (City {name: $cityName})-[:LINKED*1..3]-(city:City) RETURN city`;
const cities = [];
try{
const result = await session.run(readQuery, { cityName });
result.records.forEach(function (record) {
cities.push({
title: record._fields[0].properties.name,
});
});
return cities;
}
catch(err){
console.log(err);
return err;
}
}
I am creating a query to my postgres database. The function that makes the query looks like this:
const { pool } = require("./database");
async function getClasses(user) {
return pool.connect(async function (err, client, done) {
if (err) {
console.log(err);
} else {
const sqlText = `SELECT * FROM "public"."classes" WHERE "admins" = $1`;
const values = [user];
let listOfClasses = await client.query(sqlText, values);
done();
console.log(listOfClasses.rows);
return listOfClasses.rows;
}
});
}
module.exports = { getClasses };
The console.log(listOfClasses.rows) has the rows that I am looking for my function to return, but the actual returned value is undefined. I've been tinkering with the code for quite a while now and can't seem to figure it out. Any help here would be much appreciated.
You have to use the promise style api as the callback style call will not return anything (Your function is retuning client.connect(() => { ... }) which return undefined)
const getClasses = (...) => {
const client = await pool.connect()
const listOfClasses = await client.query(...);
return listOfClasses.rows;
}
should do
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 3 years ago.
For some reason, I can't get the following to work return a document queried from my mongodb database using the node.js driver.
function findSomething(){
const database = "learning";
const collection = "stuff";
var str;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db(database);
dbo.collection(collection).findOne({}, function(err, result) {
if (err) throw err;
str = result.name;
db.close();
});
});
return str;
}
console.log(findSomething());
This outputs
undefined
However, if I modify my above code to include the following
console.log(str);
right after
str = result.name;
It will result in the following output:
undefined
Company Inc //sample data from my document
The two things I don't understand are;
Why I can't assign str outside the .connect() function, and why the value it is assigned is lost once the connection is closed
Why the .connect() function executes after a value is returned by the findSomething() function.
I understand that my second concern will answer my first, and I am trying to do this so I can modularize my mongodb crud functions so as to make everything cleaner in my express app.
Are you looking something like this code below:
const express = require('express');
const MongoClient = require('mongodb').MongoClient;
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
class MongoDB {
async connection(connection, options = {}) {
try {
const client = await MongoClient.connect(connection.URI, options);
const db = await client.db(connection.DB);
MongoDB.db = db;
MongoDB.client = client;
} catch(ex) {
console.log(ex.message);
}
}
}
MongoDB.db = {};
MongoDB.client = {};
class MongoModel extends MongoDB {
constructor(collectionName) {
super();
this.collectionName = collectionName;
}
get collection() {
return MongoModel.db.collection(this.collectionName)
}
}
// get mongodb, for an example: import from another file
const mongodb = new MongoDB();
// connect to mongodb from 'server.js' or 'app.js'
mongodb.connection({ URI: 'mongodb://localhost:27017', DB: 'blog_dev'}, { useUnifiedTopology: true });
const somethingModel = new MongoModel('something');
// an example another collection
const anotherModel = new MongoModel('anotherCollection');
// model find
async function findSomething() {
try {
const result = await somethingModel.collection.find({}).toArray();
return result;
} catch(ex) {
console.log(ex.message);
}
}
// model create
async function createSomething(payload) {
try {
const result = await somethingModel.collection.insert(payload);
return result.ops[0];
} catch(ex) {
console.log(ex.message);
}
}
// get controller
app.get('/', async (req, res) => {
try {
const result = await findSomething();
console.log(result);
res.status(200).send(result);
} catch(ex) {
console.log(ex.message);
}
});
// create controller
app.post('/', async(req, res) => {
try {
const result = await createSomething(req.body);
res.status(200).send(result);
} catch(ex) {
console.log(ex.message);
}
})
app.listen(3000, () => console.log('Server is up on port 3000'));
There's an example simple express server using mongodb. For Advance MongoModel, you can install and learn that code in node-modules.
I hope it can help you to get a new idea.
I have a function where I would like to return an arrays of JSON objects with the necessary information. to send directly to the front everything ready.
async listProcessByOffice(req, res, next) {
try {
const actualPlayer = await PlayerOffice.findById(req.userId);
const actualOffice = await Office.findById(actualPlayer.Office);
const listProcesses = await Processes.find({ '_id': { $in: actualOffice.processes } });
const infosTable = {
protocol: ''
};
for (let i in listProcesses) {
this.protocol = listProcesses[i].prc_protocol;
console.log(this.protocol)
}
return res.status(200).json({ infosTable });
} catch (err) {
return next(err);
}
Not sure what you are looking for but i am assuming that you want to response back with array list of objects. So simple answer will be,
const infosTable = [];
for (let i in listProcesses) {
this.protocol = listProcesses[i].prc_protocol;
infosTable.push({protocol:listProcesses[i].prc_protocol})
console.log(this.protocol)
}
var Promise = require("bluebird");
var MongoDB = Promise.promisifyAll(require('mongodb'));
var MongoClient = MongoDB.MongoClient;
var database = "mongodb://localhost/test";
MongoClient.connect(database)
.then(function(db) {
var c1 = db.collection('c1');
var c2 = db.collection('c2');
return Promise.all([
c1.count().then(function(count) {
if(count==0) {
return c1.insertMany([{a:1},{a:2}]);
}
else { // what should I write here?
} //
}),
c2.count().then(function(count) {
if(count==0) {
return c2.insertMany([{a:1},{a:2}]);
}
})
]);
})
.catch(function(err) {
console.log(err)
});
It just hangs there.
And what should I write in else part?
if(count==0) {
return c1.insertMany([{a:1},{a:2}]);
}
else { // what should I write here?
} //
I guess db.collection() returns a promise as well so you need to write something like this
var Promise = require("bluebird");
var MongoDB = Promise.promisifyAll(require('mongodb'));
var MongoClient = MongoDB.MongoClient;
var database = "mongodb://localhost/test";
var insertIfEmpty = function(collection) {
collection.count().then(function(count) {
if(count==0) {
return collection.insertMany([{a:1},{a:2}]);
}
else {
return Promise.resolve()
});
}
MongoClient.connect(database)
.then(function(db) {
var promisedCollections = [db.collection('c1'), db.collection('c2')]
return Promise.all(promisedCollections).map(insertIfEmpty);
})
.catch(function(err) {
console.log(err)
});
If you need to populate the collections one at a time you can use .each in place of .map