// pretend this is a collection.
const documents = [{bar: true}, {foo: true}];
const query = {$or: [{foo: true}, {bar: true}]};
documents.findOne(query) // which document will this return?
I need to create a query like if foo, else bar. Only return bar if foo doesn’t exist.
So my question is; is the or operator deterministic so that the order in the array determines which will be output first? If not, what would the best way to have a query to do such.
If multiple documents satisfy the query, this method returns the first document according to the natural order which reflects the order of documents on the disk. In capped collections, natural order is the same as insertion order. If no document satisfies the query, the method returns null.
However, if you want more deterministic results you can use a find() query with an explicit sort() which will follow the rules of Comparison/Sort Order.
In particular, you can use the fact that null values will be sorted before boolean values to create a sort() which returns a document with foo first, if present.
// Find a document where `foo` or `bar` is true, but prefer `foo`
> db.mydata.find({$or: [{foo: true}, {bar: true}]}).sort({foo:-1}).limit(1)
{ "_id" : "foo", "foo" : true }
This query could also return { "_id": "foobar", "foo" : true, "bar" : true }, since multiple documents matching foo:true have equal value in a sort on foo. The order of result documents may not change frequently, but you should not rely on the same document being returned.
If you want a more stable order you could add additional fields to the sort criteria. For example, adding _id to the sort (since _id is guaranteed to be present and unique):
// Find a document where `foo` or `bar` is true, but prefer `foo` ordered by _id (descending)
> db.mydata.find({$or: [{foo: true}, {bar: true}]}).sort({foo:-1, _id:-1}).limit(1)
{ "_id" : "foobar", "foo" : true, "bar" : true }