How to match documents taking the order of their fields into account?

Usually the order of fields in JSON object does not matter. But it does matter for the $sort aggregation operator.
So I conclude that MongoDB preserves the order of the fields in documents it stores. Or at least is able to preserve it.

Imagine I have collection with these two documents:

{ _id: 100, hasMagneticField: -1, numberOfMoons: -1 }
{ _id: 101, numberOfMoons: -1, hasMagneticField: -1 }

Besides different ids they have different order of fields.
How to write a stage that would take the order of fields into account and selects one document, but not the other one? Of course, without using _id field.

Thanks,
Dmytro

1 Like

@Dmytro_Sheyko

Interesting question! I think you can’t, but you may wait for other comments. This is from the docs for cursor.sort(). You should check aggregation sorting in case there is any difference.

When sorting on a field which contains duplicate values, documents containing those values may be returned in any order.

If consistent sort order is desired, include at least one field in your sort that contains unique values. The easiest way to guarantee this is to include the _id field in your sort query.

Hi,

It seems I managed to create pipeline that select documents depending on field order. :sunglasses:

[{
    $addFields: {
        R: {
            $objectToArray: '$$ROOT'
        }
    }
}, {
    $addFields: {
        allfields: {
            $map: {
                input: '$R',
                as: 'it',
                'in': '$$it.k'
            }
        }
    }
}, {
    $addFields: {
        indexOf_hasMagneticField: {
            $indexOfArray: [
                '$allfields',
                'hasMagneticField'
            ]
        },
        indexOf_numberOfMoons: {
            $indexOfArray: [
                '$allfields',
                'numberOfMoons'
            ]
        }
    }
}, {
    $match: {
        $expr: {
            $and: [{
                    $lt: [ /* or $gt if you want to select another document */
                        '$indexOf_hasMagneticField',
                        '$indexOf_numberOfMoons'
                    ]
                },
                {
                    $ne: [
                        '$indexOf_hasMagneticField',
                        '-1'
                    ]
                },
                {
                    $ne: [
                        '$indexOf_numberOfMoons',
                        '-1'
                    ]
                }
            ]
        }
    }
}, {
    $unset: [ /* remove temporary fields */
        'R',
        'allfields',
        'indexOf_hasMagneticField',
        'indexOf_numberOfMoons'
    ]
}]

It was not trivial. Please let me know if it’s possible to make it more concise, efficient or correct.