|
I thought {$sort: {$arrayElemAt: ... }} might work, but it's not supported today:
> db.foo.insert({ numbers: [1, 2, 3] })
|
WriteResult({ "nInserted" : 1 })
|
> db.foo.aggregate([ {$sort: {$arrayElemAt: ["$numbers", 0]}} ])
|
2020-01-28T16:25:29.978+0000 E QUERY [js] uncaught exception: Error: command failed: {
|
"ok" : 0,
|
"errmsg" : "Illegal key in $sort specification: $arrayElemAt: [ \"$numbers\", 0.0 ]",
|
"code" : 15974,
|
"codeName" : "Location15974"
|
} : aggregate failed :
|
_getErrorWithCode@src/mongo/shell/utils.js:25:13
|
doassert@src/mongo/shell/assert.js:18:14
|
_assertCommandWorked@src/mongo/shell/assert.js:612:17
|
assert.commandWorked@src/mongo/shell/assert.js:702:16
|
DB.prototype._runAggregate@src/mongo/shell/db.js:266:5
|
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1012:12
|
@(shell):1:1
|
> db.articles.insert({ comments: [ { author: 'Alice', body: 'hello' } ] })
|
WriteResult({ "nInserted" : 1 })
|
> db.articles.aggregate([ {$sort: {$let: {vars: {firstComment: {$arrayElemAt: ["$comments", 0]}}, in: "$firstComment.author"}}} ])
|
2020-01-28T16:28:01.942+0000 E QUERY [js] uncaught exception: Error: command failed: {
|
"ok" : 0,
|
"errmsg" : "$meta is the only expression supported by $sort right now",
|
"code" : 17312,
|
"codeName" : "Location17312"
|
} : aggregate failed :
|
_getErrorWithCode@src/mongo/shell/utils.js:25:13
|
doassert@src/mongo/shell/assert.js:18:14
|
_assertCommandWorked@src/mongo/shell/assert.js:612:17
|
assert.commandWorked@src/mongo/shell/assert.js:702:16
|
DB.prototype._runAggregate@src/mongo/shell/db.js:266:5
|
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1012:12
|
@(shell):1:1
|
|
|
Yes, this is pointing out the difference in how agg treats 'paths':
test> db.foo.drop()
|
true
|
test> db.foo.insert({x: [1, 2, 3]})
|
WriteResult({
|
"nInserted": 1
|
})
|
test> db.foo.insert({x: {0: 1}})
|
WriteResult({
|
"nInserted": 1
|
})
|
test> db.foo.find({'x.0': 1}) // Finds both documents, considers 'x.0' to be the zeroth index of 'x' in the first example, and the field named '0' within 'x' in the second.
|
{
|
"_id": ObjectId("58dbc5fb9b8a5e6fdc19c24e"),
|
"x": [
|
1,
|
2,
|
3
|
]
|
}
|
{
|
"_id": ObjectId("58dbc6349b8a5e6fdc19c24f"),
|
"x": {
|
"0": 1
|
}
|
}
|
test> db.foo.aggregate([{$addFields: {cmp: {$eq: ['$x.0', 1]}}}]) // Matches only the second, since 'x.0' is always interpreted as the field named '0' within 'x'.
|
{
|
"_id": ObjectId("58dbc5fb9b8a5e6fdc19c24e"),
|
"x": [
|
1,
|
2,
|
3
|
],
|
"cmp": false
|
},
|
{
|
"_id": ObjectId("58dbc6349b8a5e6fdc19c24f"),
|
"x": {
|
"0": 1
|
},
|
"cmp": true
|
}
|
]
|
Interestingly, the projection stuff is the same...
test> db.foo.drop()
|
true
|
test> db.foo.insert({x: [1, 2, 3]})
|
WriteResult({
|
"nInserted": 1
|
})
|
test> db.foo.insert({x: {0: 4}})
|
WriteResult({
|
"nInserted": 1
|
})
|
test> db.foo.find({}, {'x.0': 1})
|
{
|
"_id": ObjectId("58dbc5fb9b8a5e6fdc19c24e"),
|
"x": [ ]
|
}
|
{
|
"_id": ObjectId("58dbc6349b8a5e6fdc19c24f"),
|
"x": {
|
"0": 4
|
}
|
}
|
test> db.foo.aggregate([{$project: {'x.0': 1}}])
|
{
|
"_id": ObjectId("58dbc5fb9b8a5e6fdc19c24e"),
|
"x": [ ]
|
},
|
{
|
"_id": ObjectId("58dbc6349b8a5e6fdc19c24f"),
|
"x": {
|
"0": 4
|
}
|
}
|
|