2015-01-21 2 views
-3

у меня есть список студенческих документов, который имеет структуру, как это:MongoDB Java: удалить элемент вложенного массива внутри документа на основе определенного состояния элементов

{ 
    "_id" : 0, 
    "name" : "aimee Zank", 
    "scores" : [ 
      { 
        "type" : "exam", 
        "score" : 1.463179736705023 
      }, 
      { 
        "type" : "quiz", 
        "score" : 11.78273309957772 
      }, 
      { 
        "type" : "homework", 
        "score" : 6.676176060654615 
      }, 
      { 
        "type" : "homework", 
        "score" : 35.8740349954354 
      } 
    ] 
} 

Как вы можете видеть, каждый студент имеет список из 4 баллов. Мне нужно удалить самую низкую оценку «домашней работы» для каждого студенческого документа. Каждый ученик имеет 2 записи для оценок типа «homewok» (последние 2 записи в массиве из 4 элементов). Схема и упорядочение типа счета согласованы и имеют одинаковый шаблон для всех учащихся. Ваша помощь приветствуется.

Это то, что я пытался достичь до сих пор:

DBCursor cursor = collection.find(); 

    try { 

     while(cursor.hasNext()) { 
      BasicDBObject doc = (BasicDBObject) cursor.next(); 
      BasicDBList scoreList = (BasicDBList) doc.get("scores"); 

      BasicDBObject hw1 = (BasicDBObject) scoreList.get("2"); 
      double hw1Score = hw1.getDouble("score"); 

      BasicDBObject hw2 = (BasicDBObject) scoreList.get("3"); 
      double hw2Score = hw2.getDouble("score"); 

      if (hw1Score > hw2Score) { 
       BasicDBObject update = new BasicDBObject("scores.score", hw2Score);    
       collection.update(doc, new BasicDBObject("$pull",update));             
      } else { 
       BasicDBObject update = new BasicDBObject("scores.score", hw1Score); 

       collection.update(doc, new BasicDBObject("$pull",update));         
      } 
      System.out.println(doc); 
     } 

    } finally { 
     cursor.close(); 
    } 


} 
+0

Вы пробовали что-нибудь для достижения этой цели?Если да, пожалуйста, поделитесь –

+0

@PradeepSimha Вероятно, не потому, что это хорошо известный вопрос о домашнем задании, заимствованный у [university.mongodb.com] (https://university.mongodb.com/) –

+1

Вы пытались выполнить поиск самого низкого балла и ' $ pull' это? – Smutje

ответ

0

Вы перебирать свой массив и найти минимальный балл. Псевдо-код:

min <- infinity 
minIndex = -1 
for index <- 0; index < elements.getScores().size(); index <- index + 1 do 
    if min > elements.getScores().get(index) then 
     min <- elements.getScores().get(index) 
     minIndex <- index 
    end if 
end for 
+0

Спасибо, но я ищу пример java для обновления документа, вытаскивая элемент из встроенного массива на основе определенных условий элементов массива. – Paaji

2

Я знаю, что это не самое лучшее решение (лучший подход, чтобы отсортировать результаты домашних заданий для каждого документа, а затем ограничить размер массива до 3). Но это тоже работает :)

 try { 

     while(cursor.hasNext()) { 
      BasicDBObject doc = (BasicDBObject) cursor.next(); 
      BasicDBList scoreList = (BasicDBList) doc.get("scores");    
      doc.remove("scores"); 

      BasicDBObject hw1 = (BasicDBObject) scoreList.get("2"); 
      double hw1Score = hw1.getDouble("score"); 

      BasicDBObject hw2 = (BasicDBObject) scoreList.get("3"); 
      double hw2Score = hw2.getDouble("score"); 

      if (hw1Score > hw2Score) {             
       scoreList.remove(3);      
      } else { 
       scoreList.remove(2);           
      } 
      doc.put("scores",scoreList); 
      collection.save(doc); 
      System.out.println(doc); 
     } 

    } finally { 
     cursor.close(); 
    }   


} 

}

0

Я попытался использовать собственные команды MongoDB, который является Preety просто выполнить. Я попробовал для данного заданного теста проверенный. Используйте приведенные ниже 2 команды, чтобы заставить его работать.

1) cursor = db.students.aggregate ([{"$ unwind": "$ score"}, {"$ match": {"scores.type": "homeework"}}, {"$ group ": {'_id': '$ _id', 'minitem': {'$ min':" $ scores.score "}}}]), null

2) cursor.forEach (function (coll) { db.students.update ({'_ id': coll._id}, {'$ pull': {'score': {'score': coll.minitem}}})})

2

попробуйте это; Я предполагаю, что высокий балл 100:

for (Document document : cursor) { 
    ArrayList<Document> list = (ArrayList<Document>) document.get("scores"); 
    double score = 100; 
    for (Document doc : list) { 
     if(doc.getString("type").equals("homework")){ 
      if(doc.getDouble("score") < score){ 
       score = doc.getDouble("score"); 
      } 
     } 
    } 
    BasicDBObject update = new BasicDBObject("scores", new BasicDBObject("score", score).append("type", "homework")); 
    collection.updateOne(document, new BasicDBObject("$pull", update));  
    } 
0

Я попытался с помощью классов Aggregater драйвера MongoDB Java, чтобы решить эту проблему. См. Ниже рабочий код для справки.

AggregateIterable<Document> aiter = collection.aggregate(
       Arrays.asList(Aggregates.unwind("$scores"),Aggregates.match(Filters.eq("scores.type", "homework")), 
         Aggregates.sort(Sorts.orderBy(Sorts.ascending("_id"), Sorts.ascending("scores.score"))))); 

     collection = database.getCollection("students"); 
     MongoCursor<Document> cursor = aiter.iterator(); 
     int pid = -1; 
     while (cursor.hasNext()) { 
      Document doc = cursor.next(); 
      int cid = doc.getInteger("_id"); 
      double scoresScore = doc.get("scores", Document.class).getDouble("score"); 
      if (pid != cid) { 
       // delete 
       BasicDBObject update = new BasicDBObject("scores", 
         new BasicDBObject("score", scoresScore).append("type", "homework")); 
       collection.updateOne(Filters.eq("_id", cid), new BasicDBObject("$pull", update)); 
      } 
      pid = cid; 
     } 
+0

Добро пожаловать в переполнение стека! Хотя вы, возможно, решили проблему этого пользователя, ответы на код не очень помогают пользователям, которые приходят к этому вопросу в будущем. Измените свой ответ, чтобы объяснить, почему ваш код решает исходную проблему. –

0

Это мой подход, возможно, кто-то найдет его чище и проще понять:

MongoClient client = new MongoClient(); 
MongoDatabase database = client.getDatabase("school"); 
final MongoCollection<BasicDBObject> collection = database.getCollection("students",BasicDBObject.class); 

MongoCursor<BasicDBObject> cursor = collection.find().iterator(); 

while(cursor.hasNext()) 
{ 
    double min_score = 999; 
    BasicDBObject doc = cursor.next(); 
    BasicDBList scores = (BasicDBList) doc.get("scores"); 

    for (Object score : scores) 
    { 
     BasicDBObject x = (BasicDBObject) score; 
     if (x.get("type").equals("homework")) 
     { 
      if (x.getDouble("score") < min_score) 
      { 
       min_score = x.getDouble("score"); 
      } 
     } 
    } 

    if (min_score == 999){ 
     continue; 
    } 

    BasicDBObject query = new BasicDBObject("_id", doc.get("_id")); // Find this Document 
    BasicDBObject fields = new BasicDBObject("scores", 
      new BasicDBObject("score", min_score)); // With those fields 
    BasicDBObject update = new BasicDBObject("$pull",fields); // And remove any the matched results. 
    collection.updateOne(query, update); 
} 

Оператор $pull удаляет из существующего массива все экземпляры значения или значения, которые соответствуют заданному условию ,

1
package com.mongodb; 

import java.util.ArrayList; 
import java.util.List; 

import org.bson.Document; 
import com.mongodb.client.MongoCollection; 
import com.mongodb.client.MongoDatabase; 

public class HWDeleteArray { 

    public static void main(String[] args) { 
     MongoClient client = new MongoClient(); 
     MongoDatabase database = client.getDatabase("school"); 
     MongoCollection<Document> collection = database.getCollection("students"); 

     List<Document> all = collection.find().into(new ArrayList<Document>()); 
     int i = 0; 
     Double s1 =0.0; 
     Double s2 =0.0; 
     Document doc1 = null; 
     Document doc2 = null; 
     for(Document cur:all) { 
      List<Document> scores = (List<Document>) cur.get("scores"); 
      for(Document score:scores) { 
       if(score.getString("type").equals("homework")) { 

        if(i==0) { 
         i++; 
         s1 = (Double) score.get("score"); 
         doc1 = score; 

        }else { 
         i--; 
         s2 = (Double) score.get("score"); 
         doc2 = score; 
         if(s1 < s2) { 
          doc1.clear(); 
          collection.replaceOne(new Document("_id",cur.get("_id")),cur); 
         }else { 
          doc2.clear(); 
          collection.replaceOne(new Document("_id",cur.get("_id")),cur); 
         } 
        } 
       } 


      } 


     } 

    } 
} 
+4

Было бы неплохо добавить, почему это ответ на проблему, а не просто отправку кода. – moondaisy

0

Попробуйте этот код:

import java.util.ArrayList; 
import java.util.List; 
import org.bson.Document; 
import org.bson.conversions.Bson; 
import static com.mongodb.client.model.Filters.eq; 

import com.mongodb.MongoClient; 
import com.mongodb.client.MongoCollection; 
import com.mongodb.client.MongoCursor; 
import com.mongodb.client.MongoDatabase; 
import com.mongodb.client.model.Projections; 


     MongoClient client = new MongoClient(); 


     String str, str2; 
     Double sub; 
     MongoDatabase db = client.getDatabase("school"); 
     MongoCollection<Document> coll = db.getCollection("students"); 
     //coll.drop(); 
     MongoCursor<Document> cursor = coll.find().iterator(); 

     List<Document> student = coll.find().into(new ArrayList<Document>()); 

     for(Document doc :student){ 
      List<Document> scores = (List<Document>)doc.get("scores"); 
      doc.remove("scores"); 


      List<Document> scores2 = scores.subList(2,3); 
      System.out.println(scores2.toString()); 
      str = (scores2.toString()).substring(32, (scores2.toString()).length()-3); 

      System.out.println(str); 

      List<Document> scores3 = scores.subList(3,4); 
      System.out.println(scores3.toString()); 
      str2 = (scores3.toString()).substring(32, (scores3.toString()).length()-3); 
      System.out.println(str2); 

      sub = Double.parseDouble(str2) - Double.parseDouble(str); 


      if(sub >0){ 
       scores.remove(2); 
       doc.put("scores", scores); 


      }else if(sub == 0){ 
       scores.remove(2); 
       doc.put("scores", scores); 
      }else{ 
       scores.remove(3); 
       doc.put("scores", scores); 
      } 
      Document cur = cursor.next(); 
      System.out.println(cur); 
      System.out.println(doc); 
      coll.findOneAndReplace(cur, doc); 

     } 
0

Я не знаю, если его лучший вариант, но работает:

List<Document> all = (List<Document>) collection.find().into(new ArrayList<Document>()); 

for (Document current : all){ 
     Object id = current.get("_id"); 
     List<Document> i = (List<Document>) current.get("scores"); 

     if(i.get(2).getDouble("score")>i.get(3).getDouble("score")){ 
      collection.updateOne(new Document("_id", id),new Document("$pull",new Document("scores",new Document("score",i.get(3).getDouble("score"))))); 
     } else{ 
      collection.updateOne(new Document("_id", id),new Document("$pull",new Document("scores",new Document("score",i.get(2).getDouble("score"))))); 

     } 
    } 
} 
0

Это мой подход к решению этой проблемы.

List<Document> documents = collection.find().into(new ArrayList<Document>()); 

    for (Document document : documents) { 
     List<Document> scores = (List<Document>) document.get("scores"); 
     Document minDoc = null; 
     for (Document score : scores) { 
      if ("homework".equals(score.getString("type")) && (minDoc == null || minDoc.getDouble("score") > score.getDouble("score"))) { 
        minDoc = score; 
       } 
     } 
     collection.updateOne(new Document("_id", document.get("_id")), new Document("$pull", new Document("scores", minDoc))); 
    } 
Смежные вопросы