How does $max work over an array of objects?

1124 views mongodb
0

Take an example collection with these documents:

client.test.foo.insert_one({
    'name': 'clientA',
    'locations': [
        {'name': 'a', 'sales': 0, 'leads': 2}, 
        {'name': 'b', 'sales': 5, 'leads': 1}, 
        {'name': 'c', 'sales': 3.3, 'leads': 1}]})
client.test.foo.insert_one({
    'name': 'clientB',
    'locations': [
        {'name': 'a', 'sales': 6, 'leads': 1},
        {'name': 'b', 'sales': 6, 'leads': 3},
        {'name': 'c', 'sales': 1.3, 'leads': 4}]})

How does $max determine which item in the location array is maximal?

client.test.foo.aggregate([{'$project': {'maxItem': {'$max': '$locations'}}}]))

Returns:

[{'_id': ObjectId('5b995d72eabb0f0d86dceda5'),
  'maxItem': {'leads': 1, 'name': 'b', 'sales': 5}},
 {'_id': ObjectId('5b995d72eabb0f0d86dceda6'),
  'maxItem': {'leads': 3, 'name': 'b', 'sales': 6}}]

It looks like $max is picking to sort on sales but I am not sure why?

answered question

1 Answer

11

I discovered this https://docs.mongodb.com/manual/reference/bson-type-comparison-order/#objects which states:

MongoDB’s comparison of BSON objects uses the following order:

  1. Recursively compare key-value pairs in the order that they appear within the BSON object.
  2. Compare the key field names.
  3. If the key field names are equal, compare the field values.
  4. If the field values are equal, compare the next key/value pair (return to step 1). An object without further pairs is less than an object with further pairs.

which means that if sales is the first key in the bson object then I have my answer. I'm using pymongo and python dictionaries aren't ordered, so I switched to bson.son.SON and re-did the example:

client.test.foo.delete_many({})
client.test.foo.insert_one({
    'name': 'clientA',
    'locations': [
        bson.son.SON([('name', 'a'), ('sales', 0), ('leads', 2)]), 
        bson.son.SON([('name', 'b'), ('sales', 5), ('leads', 1)]),
        bson.son.SON([('name', 'c'), ('sales', 3.3), ('leads', 1)])]})
client.test.foo.insert_one({
    'name': 'clientB',
    'locations': [
        bson.son.SON([('name', 'a'), ('sales', 6), ('leads', 1)]), 
        bson.son.SON([('name', 'b'), ('sales', 6), ('leads', 3)]),
        bson.son.SON([('name', 'c'), ('sales', 1.3), ('leads', 4)])]})

And now its sorting by name:

client.test.foo.aggregate([{'$project': {'maxItem': {'$max': '$locations'}}}]))

Returns:

[{'_id': ObjectId('5b99619beabb0f0d86dcedaf'),
  'maxItem': {'leads': 1, 'name': 'c', 'sales': 3.3}},
 {'_id': ObjectId('5b99619beabb0f0d86dcedb0'),
  'maxItem': {'leads': 4, 'name': 'c', 'sales': 1.3}}]

posted this

Have an answer?

JD

Please login first before posting an answer.