我只是试图在模型上调用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
哪个应该在minimal_case()函数中失败第二个断言 .
npm show mongoose
说我正在使用猫鼬5.2.5
这篇文章还提到了这一点:
sort in populate does not work (Mongoose)
在github上引用了这个问题:
https://github.com/Automattic/mongoose/issues/4481
其中说这个问题是关闭的 . 它不受支持......
但是,mongoose文档似乎提到这种语义应该可以通过它们的API实现
http://mongoosejs.com/docs/api.html#query_Query-populate
我的其他选择是
-
直接使用本机mongo语法来利用聚合管道(查找,展开,可能排序),这会使代码的可读性变得不稳定我猜
-
更改我的模型,以便我想要排序的字段直接嵌入到模型I _2810900中 . 这可能是很多工作......
-
在客户端控制器上对它进行排序,而不是让mongo为我做 . 这可能非常慢,甚至可能比排序引用的(非索引的明显)字段更慢
-
我还缺少什么?
我知道尝试对mongo中的引用字段进行连接和排序通常会影响性能,但我现在只是在做一个教程,而这种无法尝试用脚射击自己让我感到意外
UPDATE :
我添加了 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在填充后链式排序语义并在查询中指定嵌入字段 .
UPDATE :
Mongoose sort by populated field中的答案是's not possible. I guess I' ll只是在控制器代码中对其进行排序,并尝试对所查询的内容进行限制 .