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

时间:2012-11-19 08:13:57

标签: javascript arrays mongodb sorting

MongoDB noob here ...

好的,我有一个学生集合,每个学生都有一个如下所示的记录....我想按照降序排序'类型':'作业'分数。

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

但它不起作用。

15 个答案:

答案 0 :(得分:46)

您需要在应用程序代码中操作嵌入式数组,或在MongoDB 2.2中使用新的Aggregation Framework

mongo shell中的示例聚合:

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 :(得分:8)

我们如何使用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});
  })

答案 2 :(得分:3)

这是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();
    }
}
}

答案 3 :(得分:2)

这很容易猜到,但无论如何,尽量不要与mongo大学课程作弊,因为你不会理解基础知识。

./sass/style.scss'

答案 4 :(得分:2)

由于这个问题可以通过不同的方式进行管理,我想说另一个解决方案是&#34;插入和排序&#34;,这样你就可以在你创建一个Find()时得到Ordered数组。

考虑这些数据:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/detail_backdrop_height"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleTextAppearance="@android:color/transparent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/backdrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax" />

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:gravity="center_horizontal"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/love_music"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/backdrop_title"
                        android:textColor="@android:color/white"
                        android:textSize="@dimen/backdrop_title" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/backdrop_subtitle"
                        android:textColor="@android:color/white"
                        android:textSize="@dimen/backdrop_subtitle" />

                </LinearLayout>
            </RelativeLayout>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

</android.support.design.widget.CoordinatorLayout>

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

{
   "_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
       }
     }
   }
)

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

答案 5 :(得分:1)

我相信你正在做M101P: MongoDB for Developers,其中的家庭作业3.1是从两个家庭作业中删除较低的一个。由于到目前为止没有教授聚合,你可以这样做:

import pymongo

conn = pymongo.MongoClient('mongodb://localhost:27017')
db = conn.school
students = db.students

for student_data in students.find():
    smaller_homework_score_seq = None
    smaller_homework_score_val = None
    for score_seq, score_data in enumerate(student_data['scores']):
        if score_data['type'] == 'homework':
            if smaller_homework_score_seq is None or smaller_homework_score_val > score_data['score']:
                smaller_homework_score_seq = score_seq
                smaller_homework_score_val = score_data['score']
    students.update({'_id': student_data['_id']}, {'$pop': {'scores': smaller_homework_score_seq}})

答案 6 :(得分:0)

@Stennie的答案很好,也许一个$ group运算符对于保留原始文档很有用,而不会在许多文档中爆炸(一个得分)。

我只是在为您的应用程序使用javascript时添加另一种解决方案

如果只查询一个文档,它有时更容易通过JS对嵌入式数组进行排序,而不是进行聚合。 当你的文档有很多字段时,它甚至比使用$ push操作符更好,否则你可以逐个推送所有字段,或者使用$$ ROOT操作符(我错了吗?)< / p>

我的示例代码使用 Mongoose.js : 假设您已初始化学生模型。

// Sorting
function compare(a, b) {
  return a.score - b.score;
}

Students.findById('1', function(err, foundDocument){
  foundDocument.scores = foundDocument.scores.sort(compare);

  // do what you want here...
  // foundModel keeps all its fields
});

答案 7 :(得分:0)

这项工作对我来说,这是一个有点粗略的代码,但每个学生最低任务的结果是正确的。

var scores_homework = []
db.students.find({"scores.type": "homework"}).forEach(
  function(s){
    s.scores.forEach(
        function(ss){
            if(ss.type=="homework"){
                ss.student_id = s._id
                scores_homework.push(ss)
            }
        }
    )
})
for(i = 0; i < scores_homework.length; i++)
{
    var b = i+1;
    var ss1 = scores_homework[i];
    var ss2 = scores_homework[b];
    var lowest_score = {};
    if(ss1.score > ss2.score){
        lowest_score.type = ss2.type;
        lowest_score.score = ss2.score;
        db.students.update({_id: ss2.student_id},{$pull: {scores: {score: lowest_score.score}}});
    }else if(ss1.score < ss2.score){
        lowest_score.type = ss1.type;
        lowest_score.score = ss1.score;
        db.students.update({_id: ss1.student_id},{$pull: {scores: {score: lowest_score.score}}});
    }else{
        lowest_score.type = ss1.type;
        lowest_score.score = ss1.score;
        db.students.update({_id: ss1.student_id},{$pull: {scores: {score: lowest_score.score}}});
    }
    i++
}

答案 8 :(得分:0)

这是我使用pyMongo的方法,它是MongoDB的Python驱动程序:

     //Put this line in onCreate
    getListView().setPadding(0, (int) getTypedValueInDP(50), 0, 0);

   private float getTypedValueInDP(float value) {
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
}

答案 9 :(得分:0)

这就是我用Java实现的方法(保持简单,以便更容易理解) -

方法:

  1. 学生集合中获取得分数组
  2. 从得分数组中获取所有得分 type == homework
  3. 对得分值进行排序,使得最低成为第1个元素[score.get(0)]
  4. 然后,循环显示主得分并创建得分数组的新副本,同时跳过 type == homework&amp;&amp ;;得分== scores.get(0)
  5. 最后,将新得分数组更新为学生文档。
  6. 下面是Java代码:

        public void removeLowestScore(){
        //Create mongo client and database connection and get collection
        MongoClient client = new MongoClient("localhost");
        MongoDatabase database = client.getDatabase("school");
        MongoCollection<Document> collection = database.getCollection("students");
    
    
        FindIterable<Document> docs = collection.find();
        for (Document document : docs) {
    
            //Get scores array
            ArrayList<Document> scores = document.get("scores", ArrayList.class);           
    
            //Create a list of scores where type = homework
            List<Double> homeworkScores = new ArrayList<Double>();
            for (Document score : scores) {
                if(score.getString("type").equalsIgnoreCase("homework")){
                    homeworkScores.add(score.getDouble("score"));   
                }
            }
    
            //sort homework scores
            Collections.sort(homeworkScores);
    
            //Create a new list to update into student collection
            List<Document> newScoresArray = new ArrayList<Document>();
            Document scoreDoc = null;
    
            //Below loop populates new score array with eliminating lowest score of "type" = "homework"
            for (Document score : scores) {
                if(score.getString("type").equalsIgnoreCase("homework") && homeworkScores.get(0) == score.getDouble("score")){                  
                        continue;                       
                    }else{
                        scoreDoc = new Document("type",score.getString("type"));
                        scoreDoc.append("score",score.getDouble("score"));
                        newScoresArray.add(scoreDoc);
                    }               
                }           
    
            //Update the scores array for every student using student _id
            collection.updateOne(Filters.eq("_id", document.getInteger("_id")), new Document("$set",new Document("scores",newScoresArray)));
        }       
    }
    

答案 10 :(得分:0)

当然已经晚了,但我只是想在Mongo Shell上贡献自己的解决方案:

var students = db.getCollection('students').find({});
for(i = 0 ; i < students.length(); i++) {
    var scores = students[i].scores;
    var tmp = [];
    var min = -1 ;
    var valueTmp = {};
    for(j = 0 ; j < scores.length; j++) {        
        if(scores[j].type != 'homework') {
            tmp.push(scores[j]);
        } else {
            if (min == -1) {
                min = scores[j].score;
                valueTmp = scores[j];
            } else {
                if (min > scores[j].score) {
                    min = scores[j].score;
                    tmp.push(valueTmp);
                    valueTmp = scores[j];
                } else {
                    tmp.push(scores[j]);
                }
            }
        }
    }
    db.students.updateOne({_id:students[i]._id},
                            {$set:{scores:tmp}});
}

答案 11 :(得分:0)

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

1)使用展开来遍历数组

2)排序数组

3)使用组将数组的对象合并到一个数组中

4),然后投射其他字段

查询

m_SDF

答案 12 :(得分:0)

同时显示订单标题和数组标题,并返回整个集合数据集合名称为菜单

[
            {
                "_id": "5f27c5132160a22f005fd50d",
                "title": "Gift By Category",
                "children": [
                    {
                        "title": "Ethnic Gift Items",
                        "s": "/gift?by=Category&name=Ethnic"
                    },
                    {
                        "title": "Novelty Gift Items",
                        "link": "/gift?by=Category&name=Novelty"
                    }
                ],
                "active": true
            },
            {
                "_id": "5f2752fc2160a22f005fd50b",
                "title": "Gift By Occasion",
                "children": [
                    {
                        "title": "Gifts for Diwali",
                        "link": "/gift-for-diwali" 
                    },
                    {
                        "title": "Gifts for Ganesh Chathurthi",
                        "link": "/gift-for-ganesh-chaturthi",
                    }
                ],
                
                "active": true
            }
    ]

查询如下

let menuList  = await  Menu.aggregate([
                { 
                    $unwind: '$children'
                }, 
                {
                    $sort:{"children.title":1}
                },
                {   
                    $group : { _id : "$_id",
                        root: { $mergeObjects: '$$ROOT' },   
                        children: { $push: "$children" } 
                    } 
                },
                {
                    $replaceRoot: {
                        newRoot: {
                            $mergeObjects: ['$root', '$$ROOT']
                        }
                    }
                },
                {
                    $project: {
                        root: 0 
                    }
                },
                { 
                    $match: {
                                $and:[{'active':true}],
                            }
                },
                {
                    $sort:{"title":1}
                }                  
    ]);

答案 13 :(得分:-2)

按分数排序可以很简单:

db.students.find({_id:137}).sort({score:-1}).pretty()

但你需要找到一个类型:homework ...

答案 14 :(得分:-3)

它应该是这样的:

db.students.find().sort(scores: ({"score":-1}));