0

I've got a strange problem.. FIrst, take a look at my code:

This one is where I use my await..

case "detail": {
                const lineMessages = [];
                let item = await this.getItem(postback.id);
                let lineMessage = {
                        type: "text",
                        text: item.longDesc
                };
                lineMessages.push(lineMessage);
                return new Promise(function(resolve, reject) {
                    if(lineMessages != []) {
                        resolve(lineMessages);
                    }
                    else {
                        let error = new Error("Cannot catch item ${postback.id}");
                        reject(error);
                    }
                });

This is the getItem(id) method..

    getItem(id) {
    return Item.find({_id: id}).exec();
}

But it turns out the text key on my lineMessage is undefined..
Then, the lineMessage is LineMessages: [{"type":"text"}] ( I once logged it on my console)
Why await doesn't stop the execution in my case?
It seems it tries to look up item.longDesc before item is resolved (just my guess tho).
Please help

Terry Djony
  • 1,975
  • 4
  • 23
  • 41
  • Are you sure the `Item.find().exec()` method returns a `Promise`? From a first glance at the docu, it expects a callback instead. – Sirko Mar 18 '18 at 18:38
  • @Sirko `await` will actually handle a non-promise value by just returning it. – UncleDave Mar 18 '18 at 18:40
  • @UncleDave I think he meant that it might be a callback function instead of a promise function, but I'm not sure that's the case here. Could be the case that `getItem` didn't actually find the item, or some other API misusage – kingdaro Mar 18 '18 at 18:41
  • @UncleDave It will, if the returned value is actually, what you're expecting. I assume here the return value is some other object and not a promise. Hence, the execution at that step does not wait for the `find()` operation to be finished. – Sirko Mar 18 '18 at 18:41
  • 1
    Ah, true. If `exec` expects a callback then `await` won't do anything for you. – UncleDave Mar 18 '18 at 18:42
  • [According to the examples here,](http://mongoosejs.com/docs/api.html#Model) the exec function does appear to return a promise. In OP's case, it looks like the `item` variable is some kind of object, but doesn't have the `longDesc` property on it. @TerrySmith, what do you get when you `console.log(item)` after the `await`? – kingdaro Mar 18 '18 at 18:46
  • 1
    Unrelated: @Terry Smith: `lineMessages != []` can be more elegantly expressed as `lineMessages.length`. – timotgl Mar 18 '18 at 18:52

2 Answers2

0

When you require mongoose you can pass native es6 Promise to mongoose options, then you can use native promises instead of mongoose queries

const mongoose = require('mongoose');
mongoose.Promise = Promise; // or you can use bluebird. Add this line in models and before connection to database

Item.find({_id: id}).exec() // shoud return native Promise 

Or on mongoose connection options (globally)

const options = {
    promiseLibrary: global.Promise
};
mongoose.connect(uri, options);

http://mongoosejs.com/docs/connections.html

Mongoose queries is pretty weird. Item.find({_id: id}).exec() returs mongoose query, and have .then() method, but its not native js promise! When you add custom promiseLibrary to mongoose instance then Item.find({_id: id}).exec() returns native js Promise and work with async await.

Artur P.
  • 886
  • 4
  • 12
  • its still `undefined` – Terry Djony Mar 19 '18 at 00:43
  • You are shure that this.getItem(postback.id) call getItem(id) method? – Artur P. Mar 19 '18 at 00:45
  • Try this: change getItem function: `return Item.find({_id: id});` and in add exec to `let item = await this.getItem(postback.id).exec();` – Artur P. Mar 19 '18 at 00:51
  • By logging, it seems that `lineMessages` doesn't wait for the item.. I don't know why. – Terry Djony Mar 19 '18 at 01:02
  • Are you sure that in Item.model.js, after requiring mongoose you pass native promise to mongoose.Promise? `const mongoose = require('mongoose'); mongoose.Promise = Promise; ... define schema and model, export` – Artur P. Mar 19 '18 at 01:29
  • And give me detail info about this.getItem(postback.id) object `console.log(this.getItem(postback.id) instanceof Promise);` – Artur P. Mar 19 '18 at 01:33
  • Finally, I've got the answer. Item is an array actually containing a single object. I've been debugging the whole day and this is so embarassing. Thank you anyway for your answer! – Terry Djony Mar 19 '18 at 09:20
0

It turns out that mongoose findOne() returns an array with a single object, not just an object.

Terry Djony
  • 1,975
  • 4
  • 23
  • 41