2015-06-03 2 views
7

Я новичок MongoDB и я работаю над проблемой домашнего задания, набор данных выглядит следующим образомКак удалить документы, возвращенные группой в mongodb?

{ "_id" : { "$oid" : "50906d7fa3c412bb040eb577" }, "student_id" : 0, "type" : "exam", "score" : 54.6535436362647 } 
{ "_id" : { "$oid" : "50906d7fa3c412bb040eb578" }, "student_id" : 0, "type" : "quiz", "score" : 31.95004496742112 } 
{ "_id" : { "$oid" : "50906d7fa3c412bb040eb579" }, "student_id" : 0, "type" : "homework", "score" : 14.8504576811645 } 
{ "_id" : { "$oid" : "50906d7fa3c412bb040eb57a" }, "student_id" : 0, "type" : "homework", "score" : 63.98402553675503 } 
{ "_id" : { "$oid" : "50906d7fa3c412bb040eb57b" }, "student_id" : 1, "type" : "exam", "score" : 74.20010837299897 } 
{ "_id" : { "$oid" : "50906d7fa3c412bb040eb57c" }, "student_id" : 1, "type" : "quiz", "score" : 96.76851542258362 } 
{ "_id" : { "$oid" : "50906d7fa3c412bb040eb57d" }, "student_id" : 1, "type" : "homework", "score" : 21.33260810416115 } 
{ "_id" : { "$oid" : "50906d7fa3c412bb040eb57e" }, "student_id" : 1, "type" : "homework", "score" : 44.31667452616328 } 

В рамках этой проблемы я должен удалить для каждого студента, «домашнее задание» документ с самым низким счетом. Вот моя стратегия

В агрегированном трубопроводе
1: Первый фильтр всех документов типа: HomeWorks
2: Сортировать по student_id, оценка
3: сделать группу на student_id, найти первый элемент

Это даст мне все документы с самым низким счетом,

однако как я удаляю эти элементы из исходного набора данных? Любые указания или подсказки?

+0

'.remove ({})', где '' {} содержит condtions сортировки. – MegaMind

+0

Возможный дубликат [Как удалить значение min в mongodb для группы?] (Http://stackoverflow.com/questions/13298635/how-remove-min-value-in-mongodb-for-group) – Yogesh

+0

Чувак, эта домашняя работа кажется знакомые. Если вы не можете понять, как это сделать, вы должны скорее вернуться к видео уроков, чем задавать здесь. Без этих базовых знаний вы застрянете в ближайшие недели. –

ответ

13

Используйте результат курсора от агрегации в цикле через документов с forEach() методом курсора, а затем удалить каждый документ из коллекции с использованием _id в качестве запроса в методе remove(). Что-то вроде этого:

var cursor = db.grades.aggregate(pipeline); 
cursor.forEach(function (doc){ 
    db.grades.remove({"_id": doc._id}); 
}); 

Другой подход заключается в создании массива документа _id с использованием метода map() и удалить документы, как:

var cursor = db.grades.aggregate(pipeline), 
    ids = cursor.map(function (doc) { return doc._id; }); 
db.grades.remove({"_id": { "$in": ids }}); 

- UPDATE -

Для больших операций удаления может быть более эффективным копирование документов, которые вы хотите получить ep к новой коллекции, а затем используйте drop() в оригинальной коллекции. Чтобы скопировать основные документы, ваш конвейер агрегации должен вернуть документы без минимального документа домашней работы и скопировать их в другую коллекцию с использованием оператора $out в качестве конечной стадии конвейера. Рассмотрим следующий агрегацию трубопровод:

db.grades.aggregate([  
    { 
     '$group':{ 
      '_id': { 
       "student_id": "$student_id", 
       "type": "$type" 
      }, 
      'lowest_score': { "$min": '$score'}, 
      'data': { 
       '$push': '$$ROOT' 
      } 
     } 
    },  
    { 
     "$unwind": "$data" 
    }, 
    { 
     "$project": { 
      "_id": "$data._id", 
      "student_id" : "$data.student_id", 
      "type" : "$data.type", 
      "score" : "$data.score", 
      'lowest_score': 1,    
      "isHomeworkLowest": { 
       "$cond": [ 
        { 
         "$and": [ 
          { "$eq": [ "$_id.type", "homework" ] }, 
          { "$eq": [ "$data.score", "$lowest_score" ] } 
         ] 
        }, 
        true, 
        false 
       ] 
      } 
     } 
    }, 
    { 
     "$match": {"isHomeworkLowest" : false} 
    }, 
    { 
     "$project": {   
      "student_id": 1, 
      "type": 1, 
      "score": 1 
     } 
    }, 
    { 
     "$out": "new_grades" 
    } 
]) 

, в котором вы можете удалить старую коллекцию с помощью db.grades.drop(), а затем запрос на db.new_grades.find()

+0

Это самый эффективный способ сделать это? Я спрашиваю, потому что я только начал учиться. Я думал, что будет способ, когда find/deletion можно сделать в одном запросе? – Dude

+0

@Dude Для больших операций удаления может быть более эффективным копировать документы, которые вы хотите сохранить в новую коллекцию, а затем использовать drop() в исходной коллекции. – chridam

2

Я думаю, что это база данных часть домашней работы по MongoDB для разработчиков Java предусмотрено Университет МонгоДБ. Если требование состоит в том, чтобы удалить самую низкую оценку от каждого отдельного учащегося. в любом случае я решил так. Надеюсь, это будет полезно для вас. Вы можете также клонировать мой код из моей GitHub ссылки (приводится ниже)

public class Homework2Week2 { 

public static void main(String[] args) { 
    // TODO Auto-generated method stub 
    // Here the the documentation is used for mongo-jva-driver-3.2.2.jar 
    /*If you want to use different versionof mongo-jva-driver 
     then you have look for that version specificatios.*/ 
    MongoClient mongoClient = new MongoClient(); 
    // get handle to "students" database 
    MongoDatabase database = mongoClient.getDatabase("students"); 
    // get a handle to the "grades" collection 
    MongoCollection<Document> collection = database.getCollection("grades"); 
    /* 
    * Write a program in the language of your choice that will remove the grade of type "homework" with the lowest score for each student from the dataset in the handout. 
    * Since each document is one grade, it should remove one document per student. 
    * This will use the same data set as the last problem, but if you don't have it, you can download and re-import. 
    * The dataset contains 4 scores each for 200 students. 
    * First, letâs confirm your data is intact; the number of documents should be 800. 

    *Hint/spoiler: If you select homework grade-documents, sort by student 
     and then by score, you can iterate through and find the lowest score 
     for each student by noticing a change in student id. As you notice 
     that change of student_id, remove the document. 
    */ 
    MongoCursor<Document> cursor = collection.find(eq("type", "homework")).sort(new Document("student_id", 1).append("score", 1)).iterator(); 
    int curStudentId = -1; 
    try 
    { 
    while (cursor.hasNext()) { 
     Document doc = cursor.next(); 
     int studentId=(int) doc.get("student_id"); 
     if (studentId != curStudentId) { 
      collection.deleteMany(doc); 
      curStudentId = studentId; 
     } 
    } 
    }finally { 
     //Close cursor 
     cursor.close(); 
    } 
    //Close mongoClient 
    mongoClient.close(); 
} 

}

Github В моем счете у меня есть полный код проекта. Если кто-то захочет, вы можете попробовать это link.

+0

Вы можете следить за этим int studentId = Integer.valueOf (doc.get ("student_id"). ToString()); вместо этого int studentId = (int) doc.get ("student_id"); –

0

int studentId = (int) doc.get ("student_id");

дает ошибку конвертировать. Может быть, вы еще раз проверьте?

Как я знаю, мы можем сделать, как показано ниже.

int studentId = Integer.valueOf (doc.get ("student_id"). ToString());

+0

Для меня int studentId = (int) doc.get ("student_id"); работал. Ваш тоже правильный, вы можете использовать. Не могли бы вы написать мне ошибку, тогда я пойму, что происходит на самом деле? –

1
db.grades.aggregate([ 
          { 
           $match:{type:'homework'} 
          }, 
          { $group: 
           { _id: {student_id:"$student_id",type:'$type'},         
            score: { $max: "$score" } 
           } 
          } 
          ]).forEach(function(doc){ 
db.grades.remove({'student_id':doc._id.student_id,'score':doc.score}) 

}) 
Смежные вопросы