我只是尝试在模型上调用find(),通过引用填充字段,然后在某个嵌入式字段上进行排序,这似乎根本没有排序。换句话说,这似乎是一个完全的禁运。下面是我尝试的最小情况(foo.js)再现问题的尝试:
const mongoose = require('mongoose');
const process = require('process');
const assert = require('assert').strict;
const Schema = mongoose.Schema;
const DogSchema = new Schema({
name: String,
favorite_food: { type: Schema.Types.ObjectId, ref: 'Food' }
});
const FoodSchema = new Schema({
name: String
});
const Dog = mongoose.model('Dog', DogSchema);
const Food = mongoose.model('Food', FoodSchema);
async function setup() {
try {
await mongoose.connect(
'mongodb://127.0.0.1:27017/doggy_db', { useNewUrlParser: true });
}
catch (err) {
console.error(err);
process.exit(1);
}
let conn = mongoose.connection;
try {
await Promise.all([
conn.dropCollection('dogs'),
conn.dropCollection('foods')
]);
}
catch (err) {}
let chicken = new Food({ name: 'chicken' });
let hotdog = new Food({ name: 'hotdog' });
await Promise.all([
chicken.save(),
hotdog.save()
]);
await Promise.all([
new Dog({ name: 'Snoopy', favorite_food: chicken._id }).save(),
new Dog({ name: 'Buckie', favorite_food: hotdog._id }).save()
]);
return conn;
}
async function minimal_case() {
let conn = await setup();
let all_dogs = await Dog.find({})
.populate({
path: 'favorite_food',
select: 'name',
options: { sort: { name: 1 } }
});
let favorite_food_asc = all_dogs.map(dog => dog.favorite_food.name);
all_dogs = await Dog.find({})
.populate({
path: 'favorite_food',
select: 'name',
options: { sort: { name: -1 } }
});
let favorite_food_desc = all_dogs.map(dog => dog.favorite_food.name);
assert(favorite_food_asc.join(',') === 'chicken,hotdog');
assert(favorite_food_desc.join(',') === 'hotdog,chicken');
conn.close();
}
minimal_case().catch(err => {
console.error(err);
mongoose.connection.close();
})
要运行它,
$ mkdir db
$ mongod --dbpath db
和其他终端
$ node foo.js
应该使minimum_case()函数中的第二个声明失败。
npm show mongoose
说我正在使用猫鼬5.2.5
这篇文章也提到了这一点:
sort in populate does not work (Mongoose)
在github上引用了此问题:
https://github.com/Automattic/mongoose/issues/4481
表示该问题已于b.c.关闭不支持...
但是,猫鼬文档似乎提到了这种语义应该可以通过其API来实现
http://mongoosejs.com/docs/api.html#query_Query-populate
我的其他选择是
我知道尝试在mongo中引用的字段上进行联接和排序通常会影响性能,但是我现在仅在进行教程,而这种无法用脚踢自己的能力令我感到惊讶
更新:
我添加了mongoose.set('debug', true)
以打开查询打印。似乎Dog.find({}).populate({...})
可以转换为两个独立的查询(http://mongoosejs.com/docs/populate.html中的文档中甚至提到了):
Mongoose: dogs.find({}, { fields: {} })
Mongoose: foods.find({ _id: { '$in': [ ObjectId("5b59e1f5abaabb5b3a6bfe17"), ObjectId("5b59e1f5abaabb5b3a6bfe18") ] } }, { sort: { name: 1 }, fields: { name: 1 } })
我开始怀疑是否有可能告诉猫鼬在填充后对排序语义进行链接并在查询中指定嵌入式字段。
更新:
Mongoose sort by populated field中的答案表明这是不可能的。我想我只是将其排序在控制器代码中,然后尝试限制查询的内容。