LukeP LukeP - 5 months ago 5
Javascript Question

Asyncronously mapping over a collection with a function that returns a promise

I'm trying to learn how to use Bluebird promises and I am a bit lost.

I have two database tables:

topic
and
subject
.

The
topic
table has a
subject_id
column, which can then be used to query the
subject
table for the subject title.

I have an
orm
that queries asynchronously and returns a promise.

Ultimately I am trying to write a model method for topics that does the lookup for you, injecting the
subject_title
returned from the subsequent
subject
queries into the each element in the array of objects initially returned from the
topic
query.

I am trying to use
Promise.map
, but this is not working. The code below does not work. I never expected it to, but I think it captures the essence of what i am trying to accomplish.

var promise = orm.select({
db: db,
table: 'topic',
where: args.where,
order: args.order,
limit: args.limit,
offset: args.offset,
group: args.group
}).map(function (topic) {
var promise = orm.select({
db: db,
table: 'subject',
qrm: 'one',
where: {id: topic.subject_id}
}).then(function (subject) {
topic.subject_title = subject;
});
return promise;
});

return promise;


So, assuming that a vanilla
topic
object has the properties:

[subject_id, title, description]


And a
subject
object has:

[id, title]


I want the above function to return an array of objects with the following properties:

[subject_id, subject_title, title, description]


What is the cleanest way to accomplish this?

Answer

It appears that you just need to return the modified topic object from your .then() handler so it stays the fulfilled value:

return orm.select({
    db:     db, 
    table:  'topic',  
    where:  args.where,
    order:  args.order,
    limit:  args.limit,
    offset: args.offset,
    group:  args.group
}).map(function (topic) {
    return orm.select({
        db: db,
        table: 'subject',
        qrm: 'one',
        where: {id: topic.subject_id}
    }).then(function (subject) {
        topic.subject_title = subject;
        // Add return here so topic stays the fulfilled value
        return topic;
    });
});

The fullfilled value of the top level promise should be an array of modified topic objects.

Comments