如何根据Array字段的长度对文档进行排序 [英] How to sort documents based on length of an Array field

查看:74
本文介绍了如何根据Array字段的长度对文档进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的小型ExpressJS应用中,我有一个Question模型,其定义如下:

In my small ExpressJS app, I have a Question model which was defined like that

var mongoose = require('mongoose'),
    Schema   = mongoose.Schema;

/**
 * Question Schema
 */
var Question = new Schema({
  title: {
    type: String,
    default: '',
    trim: true,
    required: 'Title cannot be blank'
  },
  content: {
    type: String,
    default: '',
    trim: true
  },
  created: {
    type: Date,
    default: Date.now
  },
  updated: {
    type: Date,
    default: Date.now
  },
  author: {
    type: Schema.ObjectId,
    ref: 'User',
    require: true
  },
  answers : [{
    type: Schema.ObjectId,
    ref: 'Answer'
  }]
});

module.exports = mongoose.model('Question', Question);

我想根据答案编号列出热门问题.我用来实现目标的查询

And I want to get list popular questions based on the answer numbers. The query I used to perform my purpose

Question.find()
  .sort({'answers.length': -1})
  .limit(5)
  .exec(function(err, data) {
    if (err) return next(err);
    return res.status(200).send(data);
  });

但是我什么也没得到.有什么解决办法吗?

But I don't get anything. Do you have any solutions?

推荐答案

您在这里的意思是,您希望根据答案"数组的长度"对结果进行排序",而不是根据语法含义将其称为长度".记录下来,这里的语法是不可能的,因为您的模型是引用的",这意味着此集合的文档的array字段中存在的唯一数据是那些引用的文档的ObjectId值.

What you seem to mean here is that you want to "sort" your results based on the "length" of the "answers" array, rather than a "property" called "length" as your syntax implies. For the record, that syntax would be impossible here as your model is "referenced", meaning the only data present within the array field in the documents of this collection is the ObjectId values of those referenced documents.

但是您可以使用 .aggregate() 方法和 $size 运算符:

But you can do this using the .aggregate() method and the $size operator:

Question.aggregate(
    [
        { "$project": {
            "title": 1,
            "content": 1,
            "created": 1,
            "updated": 1,
            "author": 1,
            "answers": 1,
            "length": { "$size": "$answers" }
        }},
        { "$sort": { "length": -1 } },
        { "$limit": 5 }
    ],
    function(err,results) {
        // results in here
    }
)

聚合管道分阶段工作.首先,有一个 $project 用于结果中的字段,您可以在其中使用$size返回指定数组的长度.

An aggregation pipeline works in stages. First, there is a $project for the fields in the results, where you use $size to return the length of the specified array.

现在有一个带有长度"的字段,您可以按照以下步骤操作: $sort > $limit 用作聚合管道中自己的阶段.

Now there is a field with the "length", you follow the stages with $sort and $limit which are applied as their own stages within an aggregation pipeline.

更好的方法是始终在文档中维护答案"数组的length属性.这使得排序和查询变得很容易,而无需其他操作.使用 $inc 运营商,您 $push $pull 项,数组:

A better approach would be to alway maintain the length property of your "answers" array within the document. This makes it easy to sort and query on without other operations. Maintaining this is simple using the $inc operator as you $push or $pull items from the array:

Question.findByIdAndUpdate(id,
    {
        "$push": { "answers": answerId },
        "$inc": { "answerLength": 1 } 
    },
    function(err,doc) {

    }
)

或删除时相反:

Question.findByIdAndUpdate(id,
    {
        "$pull": { "answers": answerId },
        "$inc": { "answerLength": -1 } 
    },
    function(err,doc) {

    }
)

即使您不使用原子运算符,也遵循相同的原则来更新长度".然后进行排序查询很简单:

Even if you are not using the atomic operators, then the same principles apply where you update the "length" as you go along. Then querying with a sort is simple:

Question.find().sort({ "answerLength": -1 }).limit(5).exec(function(err,result) {

});

该属性已经存在于文档中.

As the property is already there in the document.

因此,可以使用.aggregate()进行操作,而无需更改数据,或者将数据更改为始终将长度作为属性包括在内,查询将会非常快.

So either do it with .aggregate() with no changes to your data, or change your data to alway include the length as a property and your queries will be very fast.

这篇关于如何根据Array字段的长度对文档进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆