Search code examples
node.jsmongooseaggregation-frameworkaggregate-functionsaggregation

How can I retrieve specific element from array using aggregation in Mongoose NodeJS


So I have a code for the aggregation

const documents = await deviceCollection
  .aggregate([
    {
      $match: {
        'readings.t': sensorType,
      },
    },
    { $unwind: '$readings' },
    {
      $project: {
        _id: 0,
        data: ['$readings.r', '$created_at'],
      },
    },
  ])
  .toArray();

return documents.map(({ data }) => data);

and I have a document structure like this one

{
    "readings" : [ 
        {
            "t" : "temperature",
            "r" : 6
        }, 
        {
            "t" : "humidity",
            "r" : 66
        }
    ],
    "created_at" : ISODate("2021-02-24T09:45:09.858Z"),
    "updated_at" : ISODate("2021-02-24T09:45:09.858Z")
}

I need to aggregate r value and created_at as UTC number for a particular reading type in a date range. For example, the expected output for temperature reading is:

[
 [6, 1616061903204],
 [5.6, 1616061903204]
]

But the code returns this

[
    [
        6,
        "2021-02-24T09:45:09.858Z"
    ],
    [
        66,
        "2021-02-24T09:45:09.858Z"
    ],
    [
        5.6,
        "2021-02-24T09:50:09.820Z"
    ],
    [
        68,
        "2021-02-24T09:50:09.820Z"
    ],
]

And it means that I get the humidity type value as well.


Solution

    • $match your condition
    • $unwind deconstruct readings array
    • $match again to filter readings object
    • $toLong to convert ISO date format to timestamp
    • $group by null and construct readings array in a single array
    const documents = await deviceCollection.aggregate([
      { $match: { "readings.t": sensorType } },
      { $unwind: "$readings" },
      { $match: { "readings.t": sensorType } },
      {
        $project: {
          readings: [
            "$readings.r",
            { $toLong: "$created_at" }
          ]
        }
      },
      {
        $group: {
          _id: null,
          readings: { $push: "$readings" }
        }
      }
    ]).toArray();
    
    return documents.length ? documents[0].readings : [];
    

    Playground