I want to make an openwhisk action that does something really simple: performs a find query in a mongodb and returns the result. However, since I am new in those technologies, I cannot find a solution, cause I am always recieving no results. I have connected openwhisk with the mongodb correctly. Can anyone help with a code example?
My code so far is this:
function main(){
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://192.168.1.14:27017/'
MongoClient.connect(url, (err, db) => {
db.db('yelp').collection('Review').find({stars:5}).limit(100).toArray().then((docs) => {
return docs;
db.close();
}).catch((err) => {
console.log(err.stack);
});
})
}
I am recieving null as a result. Any suggestions?
You need to use something like Promises or async/await to deal with async, and wait until the respond is back from the DB to end the action execution
See this question on how to use promises with mongodb client in nodejs
How to use MongoDB with promises in Node.js?
Related
I am trying to make a GET Request to an API and want to store the data it returns in another variable
but Javascript doesn't wait for the request to be complete and log my variable as Undefined
app.get("/", function (req, res) {
const url = "https://animechan.vercel.app/api/random";
let str = "";
let quote;
https.get(url,(resposne)=>{
resposne.on("data",(data)=>{
str+=data;
});
resposne.on("end",()=>{
const info=JSON.parse(str);
quote=info.quote;
});
});
console.log(quote);
res.render("header", {
quote: quote
});
});
I would be glad if someone can tell me how to solve this problem and where can I study about it more as I am a beginner to javascript.
Quick answer is that you need to put that code inside of response.on('end') callback.
resposne.on("end",()=>{
const info=JSON.parse(str);
quote=info.quote;
// now we can use res.render
console.log(quote);
res.render("header", {
quote: quote
});
});
However, following such approach will lead to a callback hell, unreadable and unextendable code of your project. Ideally, you should start using promises. Promises are an essential part of javascript and are a must have knowledge for a developer.
Also, I'd like to note that you don't need to implement http calls functionality from scratch or try to wrap such code into promise. Instead, it is better to use fetch api (if you are using node version 18 or above) or use corresponding libraries, for example, node-fetch.
All you have to do here is call res.send after the HTTP call is complete
app.get("/", function (req, res) {
const url = "https://animechan.vercel.app/api/random";
let str = "";
let quote;
https.get(url,(resposne)=>{
resposne.on("data",(data)=>{
str+=data;
});
resposne.on("end",()=>{
const info=JSON.parse(str);
quote=info.quote;
// Send response _after_ the http call is complete
console.log(quote);
res.render("header", {
quote: quote
});
});
});
});
I would suggest using node's fetch, since the default HTTP client is a bit less ergonomic
Fetch API reference: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
Node.js API reference: https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#fetch
I have been watching a tutorial on making a Rest API for Firestore which appears to work but I cannot figure out how to catch an error.
The code below basically uses an end point to retrieve a document id from the firestore database.
The client uses javascript fetch to call the API.
I am trying to workout how to return something back to the client from the API if the document id is not there. I thought I might get a 404 status returned but I always get status 200.
This is the API code I used
app.get("/api/read/:id", (req, res) => {
(async () => {
try {
const document = db.collection("users").doc(req.params.id);
let product = await document.get();
let response = product.data();
return res.status(200).send(response);
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
})();
})
I'm fairly certain that the 404 message is for the server itself not being found (though I do need to brush up on my error codes).
However, if you're looking to check to see if a document exists there's a command specifically for that demonstrated in the examples in the firebase docs
I am trying to make a GET request so that it only returns the last item stored in my database. I can get the answer I want in the mongo shell (see below), but I'm at a loss as to how to compose the query in my GET route. I am using ejs templates, so I will also need to pass the response through the res.render as well. I am still kind of new to programming so forgive me if this question isn't as concise as it should be.
My mongo shell query:
Blog.find().sort({_id:-1}).limit(1)
I hope the code below gives you a hint on how to structure your code using express and EJS.
app.get("/", async (req, res) => {
try {
const blogItem = await Blog.find().sort({_id:-1}).limit(1);
// Render the page with the result
res.render("your-page.ejs", { blog: blogItem });
} catch (error) {
// Handle errors here
res.render("500.ejs");
throw error;
}
});
I'm new to Mongo. I needed a database for a simple project and ended up following a tutorial using Mongo with Monk but I have problems understanding how to handle errors.
Background: I have a registration form on the client side. When the user clicks a button, the data is sent via AJAX to the controller that (upon validation, but this is not relevant now) inserts such data into the database and sends back either success or error. When the db is up all seems to work fine.
The problem: If I don't start the db and try to send the request anyway, no error is returned. Simply nothing happens. After some time on the console I get: POST /members/addmember - - ms - -.
I think some error should be returned to the user in this case, so how could I do this?
The post request is below (pretty much as from the tutorial):
// app.js
var db = monk('localhost:27017/dbname')
[...]
// I realize it might be not optimal here
app.use(function(req,res,next){
req.db = db;
next();
});
// members.js
router.post('/addmember', function(req, res) {
var db = req.db;
var collection = db.get('memberstest');
collection.insert(req.body, function(err, result){
res.json(
(err === null) ? { msg: 'success' } : { msg: err }
);
});
});
If the db is down I guess the problem is actually even earlier than the insert, that is in that "db.get()". So how to check if that get can actually be done? I suppose that given the asynchronous nature of node something like a try/catch would be pointless here. Correct?
EDIT: After Neil's answer and a bit of trying, I put together the following that seems to do the job. However, given my scarce degree of confidence on this, I'd appreciate a comment if the code below works because it makes sense or by chance. I added the bufferMaxEntries: 0 options and modified the controller as follows. In the ajax callback I simply have an alert for now that shows the error message thrown (if any).
router.post('/addmember', async (req,res) => {
try {
let db = req.db;
let collection = db.get('memberstest');
collection.insert(req.body, function(err, result){
res.json(
(err === null) ? { msg: 'success' } : { msg: err }
);
});
await db.then(() => 1);
} catch(e) {
res.json({msg: e.message})
}
});
Well you can actually set the bufferMaxEntries option ( documented under Db but deprecated for that object usage, use at "top level as demonstrated instead" ) on the connection, which essentially stops "queuing" requests on the driver when no connection is actually present.
As a minimal example:
index.js
const express = require('express'),
morgan = require('morgan'),
db = require('monk')('localhost/test',{ bufferMaxEntries: 0 }),
app = express();
const routes = require('./routes');
app.use(morgan('combined'));
app.use((req,res,next) => {
req.db = db;
next();
});
app.use('/', routes);
(async function() {
try {
await db.then(() => 1);
let collection = db.get('test');
await collection.remove({});
await collection.insert(Array(5).fill(1).map((e,i) => ({ a: i+1 })));
console.log('inserted test data');
await app.listen(3000,'0.0.0.0');
console.log('App waiting');
} catch(e) {
console.error(e);
}
})();
routes.js
var router = require('express').Router();
router.get('/', async (req,res) => {
try {
let db = req.db,
collection = db.get('test');
let response = await collection.find();
res.json(response);
} catch(e) {
res.status(500).json(e);
}
});
module.exports = router;
So I am actually awaiting the database connection to at least be present on "start up" here, but really only for example since I want to insert some data to actually retrieve. It's not required, but the basic concept is to wait for the Promise to resolve:
await db.then(() => 1);
Kind of trivial, and not really required for your actual code. But I still think it's good practice.
The real test is done by stopping mongod or otherwise making the server unreachable and then issuing a request.
Since we set the connection options to { bufferMaxEntries: 0 } this means that immediately as you attempt to issue a command to the database, the failure will be returned if there is no actual connection present.
Of course when the database becomes available again, you won't get the error and the instructions will happen normally.
Without the option the default is to "en-queue" the operations until a connection is resolved and then the "buffer" is essentially "played".
You can simulate this ( as I did ) by "stopping" the mongod daemon and issuing requests. Then "starting" the daemon and issuing requests. It should simply return the caught error response.
NOTE: Not required, but in fact the whole purpose of async/await syntax is to make things like try..catch valid again, since you can actually scope as blocks rather than using Promise.catch() or err callback arguments to trap the errors. Same principles apply when either of those structures are actually in use though.
I am want to create web server that will return data for my mobile app. I use Node.js for server and SQLite3 for database. I created method that must return data from sql, but I don't know how to do it correctly. As I know all methods from SQLite lib are async so I have no idea how to do sync request for DB. I tried this way:
app.get('/getAllLeagues',function (req, res) {
console.log("get")
var obj = db.all("SELECT name FROM Leagues")
})
But seems that obj is still the same as db object
I'm assuming that your app is an express server instance or similar. The database query function takes a callback function that is called once the queried rows are ready or an error is found.
app.get('/getAllLeagues',function (req, res) {
console.log("get")
var obj = db.all("SELECT name FROM Leagues",
function(err, rows) {
res.type('json');
res.send(rows);
});
});
For simplicity, there is no error handling. It is better to try..catch a similar request to avoid crashing your app in case the database or the table is not found.