繁体   English   中英

在 mongoDB (mongoose) 中按虚拟字段排序

[英]Sorting by virtual field in mongoDB (mongoose)

假设我有一些 Schema,它有一个像这样的虚拟字段

var schema = new mongoose.Schema(
{
    name: { type: String }
},
{
    toObject: { virtuals: true },
    toJSON: { virtuals: true }
});

schema.virtual("name_length").get(function(){
    return this.name.length;
});

在查询中是否可以按虚拟字段对结果进行排序? 就像是

schema.find().sort("name_length").limit(5).exec(function(docs){ ... });

当我尝试这个时,结果很简单,没有排序......

您将无法按虚拟字段排序,因为它们未存储到数据库中。

虚拟属性是便于使用但不会持久保存到mongodb的属性。

http://mongoosejs.com/docs/2.7.x/docs/virtuals.html

我不知道在聚合中重用现有虚拟的任何方法,但您可能能够在聚合阶段将虚拟投影到您的文档中。

我抽象了我最近构建的聚合管道。 想象一下,您有一组键,其中包含一组直接存储在团队文档中的玩家。 下面的管道将按照优先球员的排名对这些球队进行排序,其中优先球员基本上是一个虚拟财产,在某些情况下包含球队中最相关的球员(在这个例子中,我们只想考虑进攻和防守球员)。 在我们的案例中,这种情况有多种可能性,取决于用户的选择,因此无法在文档中持久化。

我们的“团队”文档非常大,并且由于投影文档仅在内存中可用,如果我们只添加一个字段并将团队集合的整个文档保存在内存中,那么它会带来巨大的性能成本。 因此我们只投影我们需要的那些字段,在限制结果后进行排序和恢复原始文档。

[
  // find all teams from germany
  { '$match': { country: 'de' } },
  // project to documents containing sort relevant fields
  // and add field favoredPlayer per team
  { '$project': {
    rank: 1,
    'favoredPlayer': {
      '$arrayElemAt': [
        {
          // remove players that should be ignored
          $filter: {
            input: '$players',
            as: 'p',
            cond: { $in: ['$$p.position', ['offense', 'defense']] },
          },
        },
        // take first of the filtered players since players are already sorted by relevance in our db
        0,
      ],
    },
  }},
  // sort teams by the ranking of the favoredPlayer
  { '$sort': { 'favoredPlayer.ranking': -1, rank: -1 } },
  { '$limit': 10 },
  // $lookup $unwind $replaceRoot to restore original database document
  { '$lookup': { from: 'teams', localField: '_id', foreignField: '_id', as: 'subdoc' } },
  { '$unwind': { path: '$subdoc' } },
  { '$replaceRoot': { newRoot: '$subdoc' } },
];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM