0

The code below is a mix of https://www.w3schools.com/nodejs/nodejs_mongodb_find.asp and https://stackoverflow.com/questions/49982058/how-to-call-an-async-function#:~:text=Putting%20the%20async%20keyword%20before,a%20promise%20to%20be%20resolved.

When you look at the console.log below the code, things seem to be running out of order. I thought by making the function async and using the .then I would avoid those issues.

I want the MongoDB data retrieval function separate from the app.get function. No data is being returned to the get request. I guess the app.get code is falling through and ending before the function returns the value. What do I need to correct?

async function getLanguageTranslationData(fromLanguage, toLanguage) {
    console.log("Started getLanguageTranslationData")
    const databaseUrl = "mongodb://localhost:27017"
    const databaseName = 'MyCompanyPOC'
    
    mongoClient.connect(databaseUrl, function(err, conn) {
        if (err) throw err; 
        const collectionName = "Phrases";
        var dbo = conn.db(databaseName)
        var query = 
                { $and: 
                       [ {masterLanguage: fromLanguage},
                         {localizedLanguage: toLanguage} 
                       ]
                }
        console.log("query=" + JSON.stringify(query)); 
        console.log("about to retrieve data"); 
        dbo.collection(collectionName).find(query).toArray( 
             function(err, result) {
                  if (err) throw err; 
                  console.log("Back from mongoDB.find()")
                  console.log(JSON.stringify(result))
                  return result 
                  conn.close()
           }) 
    })  
}


app.get("/api/gettranslations/:fromLanguage/:toLanguage", 
        async function(req, res) {
  console.log("Backend: /api/gettranslations method started: " + 
     " fromLanguage=" + req.params.fromLanguage + 
     " toLanguage=" + req.params.toLanguage)
  
  getLanguageTranslationData(
                             req.params.fromLanguage, 
                             req.params.toLanguage)
        .then((arrayResult) => { 
           console.log("got arrayResult back from getLanguageTranslationData")
           res.status(200).json(arrayResult)
           console.log("Backend: End of /api/gettranslations process")
         })
}) 

Node.JS Console output:

listening on port 3001
Backend: /api/gettranslations method started:  fromLanguage=en-US toLanguage=es-MX
Started getLanguageTranslationData
(node:44572) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
got arrayResult back from getLanguageTranslationData
Backend: End of /api/gettranslations process
query={"$and":[{"masterLanguage":"en-US"},{"localizedLanguage":"es-MX"}]}
about to retrieve data
Back from mongoDB.find()
[{"_id":"5f403f7e5036d7bdb0adcd09","masterLanguage":"en-US","masterPhrase":"Customers","localizedLanguage":"es-MX","localizedPhrase":"Clientes"},{ etc... 
NealWalters
  • 17,197
  • 42
  • 141
  • 251
  • In your code, `getLanguageTranslationData` doesn't return anything, so the `.then` executes immediately, with `arrayResult === undefined`. There are many ways to refactor your code to make it work, but I guess the simplest one is just to ditch `getLanguageTranslationData` and move its code back inside `app.get`, unless you need it elsewhere - in this case you should look into calling `mongoClient.connect()` outside `getLanguageTranslationData`, so you could make the latter `return dbo.collection(collectionName).find(query).toArray()`. – dalmo Aug 26 '20 at 21:31
  • Thanks. So the "return result" doesn't count as a return? I was trying to reduce the amount of nested code and chasing down closing braces/parentheses errors. And eventually, it might be a data access layer in another module. – NealWalters Aug 26 '20 at 21:37
  • This might be what I'm trying to do. It uses a callback. I will try it: https://stackoverflow.com/questions/35246713/node-js-mongo-find-and-return-data – NealWalters Aug 26 '20 at 21:46

2 Answers2

1

The thing is getLanguageTranslationData should return a promise so that you can use it as a promise in your handler, but in your case, call to getLanguageTranslationData will return undefined as all the code inside this function will execute asynchronously due to nodejs non-blocking nature.

So what you can do is return promise from your getLanguageTranslationData function like this.

function getLanguageTranslationData(fromLanguage, toLanguage) {
    const databaseUrl = "mongodb://localhost:27017"
    const databaseName = 'MyCompanyPOC'
    
    return new Promise((resolve, reject)=>{
        mongoClient.connect(databaseUrl, function(err, conn) {
            if (err) reject(err); 
            else{
                const collectionName = "Phrases";
                var dbo = conn.db(databaseName)
                var query = 
                        { $and: 
                               [ {masterLanguage: fromLanguage},
                                 {localizedLanguage: toLanguage} 
                               ]
                        }
                dbo.collection(collectionName).find(query).toArray( 
                     function(err, result) {
                          if (err) reject(err); 
                          else
                          resolve(result);    
                   }) 
            }
           
        }) 
    }) 
}

and then use await in your handler to use that promise returned

app.get("/api/gettranslations/:fromLanguage/:toLanguage", 
  async function(req, res) {
      try{
        let arrayResult = await getLanguageTranslationData(req.params.fromLanguage, req.params.toLanguage);
        res.status(200).json(arrayResult)
      }catch(err){
        // return error
      }
}) 

The above code will give you the gist of what you need to do, actual code may vary according to your needs.

You can refer async-await from here

namar sood
  • 1,580
  • 1
  • 9
  • 17
  • Thanks, see my other answer. I was typing and testing at the same time your were posting. Up-to-date drivers have support for promises, The link I refer to shows both ways. – NealWalters Aug 26 '20 at 22:14
0

I got it working in this way, based on this example: Node.js, Mongo find and return data

@Namar's answer is probably correct too, but I was testing this the same time he posted. As the StackOverflow question/answer above notes, the up-to-date versions of MongoClient have support for promises. That post also shows how to put in a separate module, which is something I will probably do later this week.

function getLanguageTranslationData(fromLanguage, toLanguage) {
    console.log("Started getLanguageTranslationData")
    const databaseUrl = "mongodb://localhost:27017"
    const databaseName = 'ShedCompanyPOC'
    
    return mongoClient.connect(databaseUrl)
        .then(function(conn) {
            var collectionName = "UploadedDataeFromExcel";
            var dbo = conn.db(databaseName)
            var query = 
                    { $and: 
                           [ {masterLanguage: fromLanguage},
                             {localizedLanguage: toLanguage} 
                           ]
                    }
            console.log("query=" + JSON.stringify(query)); 
            console.log("about to retrieve data"); 
            var collection = dbo.collection(collectionName)
            return collection.find(query).toArray(); 
        }).then(function(result) {
              console.log("Back from mongoDB.find()")
              console.log(JSON.stringify(result))
              //conn.close()
              return result
        }); 
    }



app.get("/api/gettranslations/:fromLanguage/:toLanguage", 
        async function(req, res) {
  console.log("Backend: /api/gettranslations method started: " + 
     " fromLanguage=" + req.params.fromLanguage + 
     " toLanguage=" + req.params.toLanguage)
  
  getLanguageTranslationData(
                             req.params.fromLanguage, 
                             req.params.toLanguage)
        .then(function(arrayResult) {
           console.log("got arrayResult back from getLanguageTranslationData")
           res.status(200).json(arrayResult)
           console.log("Backend: End of /api/gettranslations process")
         }, function(err) {
             console.log("The promise was rejected", err, err.stack)
         })
}) 
NealWalters
  • 17,197
  • 42
  • 141
  • 251