如何在MongoDB中的集合记录中对数组进行排序?

IT技术 javascript arrays mongodb sorting
2021-01-26 13:25:34

MongoDB 菜鸟在这里...

好的,我有一组学生,每个学生都有一个类似于以下的记录......我想按降序对“类型”:“家庭作业”分数进行排序。

这个咒语在 mongo shell 上是什么样子的?

> db.students.find({'_id': 1}).pretty()
{
        "_id" : 1,
        "name" : "Aurelia Menendez",
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 60.06045071030959
                },
                {
                        "type" : "quiz",
                        "score" : 52.79790691903873
                },
                {
                        "type" : "homework",
                        "score" : 71.76133439165544
                },
                {
                        "type" : "homework",
                        "score" : 34.85718117893772
                }
        ]
}

我正在尝试这个咒语......

 doc = db.students.find()

 for (_id,score) in doc.scores:
     print _id,score

但它不起作用。

6个回答

您将需要在应用程序代码中操作嵌入的数组或使用MongoDB 2.2 中的新聚合框架

mongoshell 中的聚合示例

db.students.aggregate(
    // Initial document match (uses index, if a suitable one is available)
    { $match: {
        _id : 1
    }},

    // Expand the scores array into a stream of documents
    { $unwind: '$scores' },

    // Filter to 'homework' scores 
    { $match: {
        'scores.type': 'homework'
    }},

    // Sort in descending order
    { $sort: {
        'scores.score': -1
    }}
)

示例输出:

{
    "result" : [
        {
            "_id" : 1,
            "name" : "Aurelia Menendez",
            "scores" : {
                "type" : "homework",
                "score" : 71.76133439165544
            }
        },
        {
            "_id" : 1,
            "name" : "Aurelia Menendez",
            "scores" : {
                "type" : "homework",
                "score" : 34.85718117893772
            }
        }
    ],
    "ok" : 1
}
您可以将聚合管道的末尾更改为升序排序(因此最低的在前)并限制为 1 个文档:` { $sort: { 'scores.score': 1 }}, { $limit : 1 }`
2021-04-03 13:25:34
@FOO 这个问题已有 6.5 年的历史,现在有不同的选项,具体取决于您的 MongoDB 服务器版本。请发布一个新问题,其中包含与您的环境和您要解决的问题相关的详细信息。
2021-04-05 13:25:34
@PrabjotSingh 我不完全清楚您的问题是什么,但与其在评论中讨论,您应该发布一个新问题,其中包含您的文档结构、所需输出和 MongoDB 服务器/驱动程序版本的示例。
2021-04-06 13:25:34
重复数据的问题,您将在每个对象中重复名称。所以如果我在上层有 20 个字段,那么我应该重复吗?
2021-04-08 13:25:34
我同意 @PrabjotSingh 分数作为嵌入式数组返回吗?就像问题所暗示的那样。
2021-04-08 13:25:34

由于可以通过不同方式管理这个问题,我想说另一种解决方案是“插入和排序”,这样您将在进行 Find() 时获得 Ordered 数组。

考虑这个数据:

{
   "_id" : 5,
   "quizzes" : [
      { "wk": 1, "score" : 10 },
      { "wk": 2, "score" : 8 },
      { "wk": 3, "score" : 5 },
      { "wk": 4, "score" : 6 }
   ]
}

在这里,我们将更新文档,进行排序。

db.students.update(
   { _id: 5 },
   {
     $push: {
       quizzes: {
          $each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
          $sort: { score: -1 },
          $slice: 3 // keep the first 3 values
       }
     }
   }
)

结果是:

{
  "_id" : 5,
  "quizzes" : [
     { "wk" : 1, "score" : 10 },
     { "wk" : 2, "score" : 8 },
     { "wk" : 5, "score" : 8 }
  ]
}

文档:https : //docs.mongodb.com/manual/reference/operator/update/sort/#up._S_sort

我们可以在存储的数组字段上使用 $each 吗?
2021-03-15 13:25:34

这就是我们如何用 JS 和 mongo 控制台解决这个问题:

db.students.find({"scores.type": "homework"}).forEach(
  function(s){
    var sortedScores = s.scores.sort(
      function(a, b){
        return a.score<b.score && a.type=="homework";
      }
    );
    var lowestHomeworkScore = sortedScores[sortedScores.length-1].score;
    db.students.update({_id: s._id},{$pull: {scores: {score: lowestHomeworkScore}}}, {multi: true});
  })
@TreefishZhang 为什么不应该呢?
2021-03-14 13:25:34
伙计?你破坏了乐趣。
2021-03-23 13:25:34
@AlexanderPanasyuk 它取得了什么成就?-它过滤掉了一些学生吗?
2021-04-03 13:25:34
{"scores.type": "homework"}find() 中过滤器表达式是否实现了什么功能?
2021-04-05 13:25:34

这是 Java 代码,可用于找出数组中的最低分数并将其删除。

public class sortArrayInsideDocument{
public static void main(String[] args) throws UnknownHostException {
    MongoClient client = new MongoClient();
    DB db = client.getDB("school");
    DBCollection lines = db.getCollection("students");
    DBCursor cursor = lines.find();
    try {
        while (cursor.hasNext()) {
            DBObject cur = cursor.next();
            BasicDBList dbObjectList = (BasicDBList) cur.get("scores");
            Double lowestScore = new Double(0);
            BasicDBObject dbObject = null;
            for (Object doc : dbObjectList) {
                BasicDBObject basicDBObject = (BasicDBObject) doc;
                if (basicDBObject.get("type").equals("homework")) {
                    Double latestScore = (Double) basicDBObject
                            .get("score");
                    if (lowestScore.compareTo(Double.valueOf(0)) == 0) {
                        lowestScore = latestScore;
                        dbObject = basicDBObject;

                    } else if (lowestScore.compareTo(latestScore) > 0) {
                        lowestScore = latestScore;
                        dbObject = basicDBObject;
                    }
                }
            }
            // remove the lowest score here.
            System.out.println("object to be removed : " + dbObject + ":"
                    + dbObjectList.remove(dbObject));
            // update the collection
            lines.update(new BasicDBObject("_id", cur.get("_id")), cur,
                    true, false);
        }
    } finally {
        cursor.close();
    }
}
}
好的!很好的例子...使用 java 8 我们可以最小化比较部分。
2021-03-17 13:25:34
@Vel 如何dbObjectDBObject 中删除from dbObjectList、 remove curcur之间有什么联系dbObjectList
2021-03-23 13:25:34

为了对数组进行排序,请按照下列步骤操作:

1)使用 unwind 遍历数组

2)排序数组

3)使用 group 将数组的对象合并为一个数组

4)然后投影其他领域

询问

db.taskDetails.aggregate([
    {$unwind:"$counter_offer"},
    {$match:{_id:ObjectId('5bfbc0f9ac2a73278459efc1')}},
    {$sort:{"counter_offer.Counter_offer_Amount":1}},
   {$unwind:"$counter_offer"},
   {"$group" : {_id:"$_id",
    counter_offer:{ $push: "$counter_offer" },
    "task_name": { "$first": "$task_name"},
    "task_status": { "$first": "$task_status"},
    "task_location": { "$first": "$task_location"},
}}

]).pretty()
与 相反$addToSet, using$push保留了在上一步中排序的数组的顺序。
2021-03-21 13:25:34