javascriptmongodbrealmmongodb-realmrealm-functions

How to map over results in Realm custom resolver function find() response?


I am trying to create a function for my custom resolver that gets all documents in a collection and returns an amended payload with new data. Below is the code that im using to get one client and amend its data:

exports = (input) => {
  const clientId = input._id;
  const openStatusId = new BSON.ObjectId("898999");
  
  const mongodb = context.services.get("mongodb-atlas");
  const clientRecords = mongodb.db("db-name").collection("clients");
  const jobRecords = mongodb.db("db-name").collection("jobs");
  
  let client = clientRecords.findOne({"_id": clientId});
  const query = { "client_id": clientId};

  let jobsForClient = jobRecords.count(query)
  .then(items => {
    console.log(`Successfully found ${items} documents.`)
    // items.forEach(console.log)
    return items
  })
  .catch(err => console.error(`Failed to find documents: ${err}`));
  
  let openJobs = jobRecords.count({"client_id": clientId,"status": openStatusId})
  .then(numOfDocs => {
    console.log(`Found ${numOfDocs} open jobs.`)
    // items.forEach(console.log)
    return numOfDocs
  })
  .catch(err => console.error(`Failed to find documents: ${err}`));
  
  return Promise.all([client, jobsForClient, openJobs]).then(values => {
    return {...values[0], "jobs": values[1], "openJobs": values[2]}
  })
};

How can i fix this function to get all clients and loop over them to add data to each client? I understand that changing this: let client = clientRecords.findOne({"_id": clientId}); to this let clients = clientRecords.find();

will get all the documents from the clients collection. How would i loop over each client after that?

UPDATE:

I have updated the function to the below and it works when running it in the realm environment but gives me an error when running it as a GraphQL query.

Updated code:

exports = (input) => {
  const openStatusId = new BSON.ObjectId("999999");
  
  const mongodb = context.services.get("mongodb-atlas");
  const clientRecords = mongodb.db("db-name").collection("clients");
  const jobRecords = mongodb.db("db-name").collection("jobs");
  
  const clients = clientRecords.find();

  const formatted = clients.toArray().then(cs => {
    return cs.map((c,i) => {
      const clientId = c._id;
      const query = { "client_id": clientId};
      
      let jobsForClient = jobRecords.count(query)
      .then(items => {
        console.log(`Successfully found ${items} documents.`)
        // items.forEach(console.log)
        return items
      })
      .catch(err => console.error(`Failed to find documents: ${err}`));
      
      let openJobs = jobRecords.count({"client_id": clientId,"status": openStatusId})
      .then(numOfDocs => {
        console.log(`Found ${numOfDocs} open jobs.`)
        // items.forEach(console.log)
        return numOfDocs
      })
      .catch(err => console.error(`Failed to find documents: ${err}`));
      
      return Promise.all([jobsForClient, openJobs]).then(values => {
        return {...c, "jobs": values[0], "openJobs": values[1]}
      });
    })
  }).catch(err => console.error(`Failed: ${err}`));
  
  return Promise.all([clients, formatted]).then(values => {
        return values[1]
      }).catch(err => console.error(`Failed to find documents: ${err}`));
};

Error in GraphQL: "message": "pending promise returned that will never resolve/reject",


Solution

  • Managed to solve by using mongodb aggregate. Solution below:

    exports = async function(input) {
    
    
    const openStatusId = new BSON.ObjectId("xxxxxx");
      
      const mongodb = context.services.get("mongodb-atlas");
      const clientRecords = mongodb.db("xxxxx").collection("xxxx");
      const jobRecords = mongodb.db("xxxxx").collection("xxxx");
      
      return clientRecords.aggregate([
          {
              $lookup: {
                  from: "jobs",
                  localField: "_id",
                  foreignField: "client_id",
                  as: "totalJobs"
              }
          },
          {
              $addFields: {
                jobs: { $size: "$totalJobs" },
                openJobs: {
                  $size: {
                    $filter: {
                      input: "$totalJobs",
                      as: "job",
                      cond: { "$eq": ["$$job.status", openStatusId]},
                    }
                  }
                },
              }
          }
      ]);
    };