猫鼬查找,填充,排序未排序

时间:2018-07-26 10:52:37

标签: node.js mongodb sorting mongoose

我只是尝试在模型上调用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

我的其他选择是

  1. 直接使用本机mongo语法来利用聚合流水线(可能是查找,展开,排序),这会使代码的可读性差强人意。
  2. 更改我的模型,以便将要排序的字段直接嵌入正在执行查询的模型中,从而无需填充。这可能是很多工作...
  3. 在客户端控制器上对它进行排序,而不是让mongo为我做。这可能确实很慢,甚至可能比对引用的(显然没有索引的)字段进行排序
  4. 我想念的还有什么吗?

我知道尝试在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中的答案表明这是不可能的。我想我只是将其排序在控制器代码中,然后尝试限制查询的内容。

0 个答案:

没有答案