Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dataloader did not return an array of the same length?

I Am building an express JS application with graphql, and mongodb (mongoose). I am using facebooks Dataloader to batch and cache requests.

Its working perfectly fine except for this use case.

I have a database filled with users posts. Each post contains the users ID for reference. When i make a call to return all the posts in the database. The posts are returned fine but if i try to get the user in each post. Users with multiple posts will only return a single user because the key for the second user is cached. So 2 posts(keys) from user "x" will only return 1 user object "x".

However Dataloader has to return the same amount of promises as keys that it recieves.

It has a option to specify cache as false so each key will make a request. But this doesnt seem to work for my use case.

Sorry if i havn't explained this very well.

this is my graphql request

query {
  getAllPosts {
    _id // This is returned fine
    user {
      _id
     }
   }
 }

Returned error:
DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array of the same length as the Array of keys.

like image 338
tygar Avatar asked Jan 19 '26 14:01

tygar


1 Answers

are you trying to batch post keys [1, 2, 3] and expecting to get user results [{ user1 }, {user2}, { user1 }]?

or are you trying to batch user keys [1, 2] and expecting to get post results [{ post1}, {post3}] and [{ post2 }]?

seems like only in the second case will you run into a situation where you have length of keys differing from length of results array.

to solve the second, you could do something like this in sql:

const loader = new Dataloader(userIDs => {
  const promises = userIDs.map(id => {
    return db('user_posts')
      .where('user_id', id);
  });

  return Promise.all(promises);
})

loader.load(1)
loader.load(2)

so you return [[{ post1}, {post3}], [{ post2 }]] which dataloader can unwrap.

if you had done this instead:

const loader = new Dataloader(userIDs => {
  return db('user_posts')
      .where('user_id', [userIDs]);
})

loader.load(1)
loader.load(2)

you will instead get [{ post1}, {post3}, { post2 }] and hence the error: the function did not return a Promise of an Array of the same length as the Array of keys

not sure if the above is relevant / helpful. i can revise if you can provide a snippet of your batch load function

like image 155
Shem Leong Avatar answered Jan 22 '26 20:01

Shem Leong