我只是试图在模型上调用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只是在控制器代码中对其进行排序,并尝试对所查询的内容进行限制 .