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

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

问题描述

在我的小型 ExpressJS 应用程序中,我有一个这样定义的问题模型

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?

推荐答案

您在这里的意思似乎是您想根据答案"数组的长度"对结果进行排序",而不是根据语法暗示的称为长度"的属性".作为记录,这种语法在这里是不可能的,因为您的模型是引用"的,这意味着该集合文档中数组字段中存在的唯一数据是这些引用文档的 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.

更好的方法是始终保持文档中答案"数组的长度属性.这使得无需其他操作即可轻松进行排序和查询.使用 $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.

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

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