How do I iterate over several arrays and create a new object array

I’ve got the following data:

[
  {
    "RunInfo": {
      "Errors:": [
        0,
        0,
        0
      ],
      "load": [
        108422760,
        259103136,
        220934960
      ],
      "timestamp": [
        "2022-09-07T01:51:32Z",
        "2022-09-07T01:52:31Z",
        "2022-09-07T01:53:31Z"
      ],
      "Mem": [
        1335040,
        1335040,
        1335040
      ]
    },
    
  }
]

Can I query this so that I get it returned as one array of objects (each with timestamp,Error,load,mem) and then have it sorted by timestamp?

I’ve been having a hack around with the following:

db.collection.aggregate([
  {
    "$unwind": "$RunInfo"
  },
  {
    "$set": {
      "RunInfo.timestamp": {
        "$arrayElemAt": [
          "$values"
        ]
      }
    }
  },
  {
    "$group": {
    }
  }
])

However I’m not following how to get through several collections at once and then re-create as new objects.

Any help would be appreciated.

Please provide a sample result document based on the input document you shared.

It might be good to have different input data for errors and mem.

Look $range and $map as they are probably needed in the solution.

Two more things.

  1. If consolidating the 4 arrays is a frequent use-case, you should consider doing when you store the document.

  2. Personally, I prefer doing this type of data cosmetic in the application side rather than the server. Imagine you have 1000 different users doing this aggregation, they all impact the server. But they could do a simple for-loop in the application and the load of doing the consolidation will be distributed among the users.

Yes you can. There are a few ways to do it, one is using $zip:

 db.arrays.find({},
    {combined:{$zip:{inputs:["$RunInfo.Errors:", "$RunInfo.load", "$RunInfo.timestamp", "$RunInfo.Mem"]}}})
{
"_id" : ObjectId("6321e5278a58698cf4bc2758"),
"combined" : [
	[
		0,
		108422760,
		"2022-09-07T01:51:32Z",
		1335040
	],
	[
		0,
		259103136,
		"2022-09-07T01:52:31Z",
		1335040
	],
	[
		0,
		220934960,
		"2022-09-07T01:53:31Z",
		1335040
	]
]
}

As you can see, the field name are not preserved this way, so you might prefer to do something like:

db.arrays.find({},{combined:{$map:{
      input:{$range:[0,{$size:"$RunInfo.Errors:"}]}, 
      as:"idx", 
      in:{ 
         "Errors:" : { "$arrayElemAt" : [ "$RunInfo.Errors:", "$$idx" ] }, 
         "load" : { "$arrayElemAt" : [ "$RunInfo.load", "$$idx" ] }, 
         "timestamp" : { "$arrayElemAt" : [ "$RunInfo.timestamp", "$$idx" ] }, 
         "Mem" : { "$arrayElemAt" : [ "$RunInfo.Mem", "$$idx" ] } 
      } 
 }}})
{
"_id" : ObjectId("6321e5278a58698cf4bc2758"),
"combined" : [
	{
		"Errors:" : 0,
		"load" : 108422760,
		"timestamp" : "2022-09-07T01:51:32Z",
		"Mem" : 1335040
	},
	{
		"Errors:" : 0,
		"load" : 259103136,
		"timestamp" : "2022-09-07T01:52:31Z",
		"Mem" : 1335040
	},
	{
		"Errors:" : 0,
		"load" : 220934960,
		"timestamp" : "2022-09-07T01:53:31Z",
		"Mem" : 1335040
	}
]
}

If you’re on the latest version, you can then $sortArray on timestamp field.

(Note your sample document has Errors field as Errors: - extra semicolon - which might cause issues with testing)

1 Like