skip to Main Content

I am querying the database using findOne which will return just one document. Now, I want a few of the fields of that document in one object and the other fields in the other object, both of which are wrapped in a single object. For example I have a table called Bus with the following fields –

_id,
busNo,
city,
agency,
date,
ticketPrice,
helper,
driver,
totalCollection

My find one query returns one document but I want it in the below format –

existingAggr -  {
  "result": [
    {
      "_id": "630dcd0c652489bca1b319f7",
      "busNo": "123",
      "city": "32",
      "agency": "58",
      "date": "2022-08-29T00:00:00.000Z",
    }
  ],
  "aggregates": {
    "ticketPrice": 8,
    "totalCollection": 402,
    "helper": 0,
    "driver": 23,
  }
}

I want this either with single access of database, or we can do some javascript calculations to further bring my result in this manner, but I cant seem to reach the solution. Currently, I am using the below code –

const res = await Bus.findOne(
    { busNo, date },
    { 
     _id :1,
     busNo:1, 
     city:1,
     agency:1,
     date:1,
     ticketPrice:1,
     helper:1,
     driver:1,
     totalCollection:1
   }
  );

This would return all the fields in one.

2

Answers


  1. Given a result, you can straightfowardly create new objects from your result.

    const res = await BusDayWise.findOne(
        { ...filter },
        { session: mongoSession }
      );
    
    const result = [
        {
          "_id": res._id,
          "busNo": res.busNo,
          "city": res.city,
          "agency": res/agency,
          "date": res.date,
        }
    ],
    const aggregates = 
    {
        "ticketPrice": res.ticketPrice,
        "totalCollection": res.totalCollection,
        "helper": res.helper,
        "driver": res.driver,
    }
    

    More advanced answer

    You can have a function that retrieve only certain key from a dictionnary

    function subDict(dict, keys){
       const newDict = {};
       keys.forEach(key => newDict[key] = dict[key]);
       return newDict 
    }
    
    test = {"a": 1, "b": 2, "c": 3}
    keys = ["a", "c"];
    newTest = subDict(test, keys); // {"a": 1; "c": 3}
    

    So in your case

    const result = subDict(res, ["_id", "busNo", "city","agency", "date"]);
    const aggregates = subDict(res, ["ticketPrice", "totalCollection", "helper", "driver"]);
    
    Login or Signup to reply.
  2. This should be pretty straightforward to do with projection which is the act of transforming the shape of the documents.

    Your edited question now includes a reference to the simplest type of projection, but there are many more. In your case it looks like you can still use a relatively simple one, try this:

    {
      "result._id": "$_id",
      "result.busNo": "$busNo",
      "result.city": "$city",
      "result.agency": "$agency",
      "result.date": "$date",
      "aggregates.ticketPrice": "$ticketPrice",
      "aggregates.totalCollection": "$totalCollection",
      "aggregates.helper": "$helper",
      "aggregates.driver": "$driver",
      _id: 0
    }
    

    Playground demonstration here.

    If you are going to be doing this every time you retrieve the data then you may wish to change the schema of the documents as they are stored in the database. Alternatively, you could create a view that defines this projection which would then be automatically applied every time you query the data and not have to rely on the client to request it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search