Does $setUnion expression operator order array elements in ascending order?

The real work of $setUnion operator is to filters out duplicates in its result to output an array that contain only unique entries.

I have workaround $setUnion operator orders element in ascending order on the base of first field of element, is that true?

Sample documents:

[{ "key1": 1, "key2": "R" },
{ "key1": 2, "key2": "Q" },
{ "key1": 2, "key2": "Q" },
{ "key1": 3, "key2": "P" },
{ "key1": 3, "key2": "P" },
{ "key1": 3, "key2": "P" },
{ "key1": 4, "key2": "O" }]

First query, key1 would be first and key2 would be second, means this will result in ascending order by key1 field,

db.collection.aggregate([
  {
    $group: {
      _id: null,
      root: { $push: { key1: "$key1", key2: "$key2" } }
    }
  },
  { $project: { root: { $setUnion: "$root" } } }
])

First query, key2 would be first and key1 would be second, means this will result in ascending order by key2 field,

db.collection.aggregate([
  {
    $group: {
      _id: null,
      root: { $push: { key2: "$key2", key1: "$key1" } }
    }
  },
  { $project: { root: { $setUnion: "$root" } } }
])

I looked at the MongoDB $setUnion Documentation, they have mentioned statement: The order of the elements in the output array is unspecified., but this query returns in exact order by first field,

Please suggest or refer me if i am missing to refer any MongoDB documentation, and please if anyone confirm this is a feature then i will implement in my code.

Hi @turivishal,

Although the operator outputs the data according to your desired output it cannot guarantee this order will maintain , its only circumstantially.

If you wish to guarantee the order of the output please use a $sort stage after the $setUnion to guarantee your order.

Best
Pavel

1 Like

Thank you very much for your reply,

Actually i am using $addToSet instead of $push in $group stage, but $addToSet unorder the array, my actual query is:

I know the behavior of $addToSet operator, it will not guarantee the order of array,

db.collection.aggregate([
  { $sort: { key1: 1 } },
  {
    $group: {
      _id: null,
      root: { $addToSet: { key1: "$key1", key2: "$key2" } }
    }
  }
])

So to prevent this problem, I have used below query and It is working perfectly, and i don’t need to use $unwind and again $group

db.collection.aggregate([
  {
    $group: {
      _id: null,
      root: { $addToSet: { key1: "$key1", key2: "$key2" } }
    }
  },
  { $project: { root: { $setUnion: "$root" } } }
]) 

If its save 2 stages $unwind and $group for sorting then its really good feature for us.

I have tested many examples its working perfectly, if it is circumstantially then could you please share some example that is not circumstantially.

Hi @turivishal, I can’t provide you with an example for which your code won’t work (I haven’t tried) but to ensure it’s always sorted you may want to consider using a custom aggregation expression. That way you can control the order. Note that this only works if you are using MongoDB 4.4.