簡體   English   中英

Mongodb Java:根據元素的某些條件刪除文檔中嵌入式數組的元素

[英]Mongodb Java: remove an element of an embedded array within a document based on certain condition of elements

我有一份學生文件清單,其結構如下:

{
    "_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”類型分數的條目(4個元素的數組中的最后2個條目)。 分數類型的模式和順序是一致的,並且對所有學生都具有相同的模式。非常感謝您的幫助。

到目前為止,這是我試圖實現的目標:

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


}

我知道這不是最佳解決方案(更好的方法是對每個文檔的作業分數進行排序,然后將數組大小限制為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();
    }        


}

}

嘗試這個; 我認為最高分是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));     
    }

這里的所有答案都很好。 我只是想補充一下,如果有人想使用Java運算符(從驅動程序v3.1開始),那么他可以使用以下方法而不是使用“ $ pull”運算符:

...
Bson studentFilter = Filters.eq( "_id", doc.get("_id") );
Bson delete = Updates.pull("scores", new Document("score", lowestHomework).append("type", "homework"));
collection.updateOne(studentFilter, delete);

我認為這更優雅。 所以我的完整答案是:

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

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

    for(Document doc : homeworks)
    {
        ArrayList<Document> scores = (ArrayList<Document>) doc.get("scores");
        //iterate over the scores of each student (there are 4 scores: quiz, exam and 2*homework)
        double lowestHomework = Double.MAX_VALUE;
        for(Document embeddedDoc : scores)
        {
            if(embeddedDoc.getString("type").equals("homework"))
            {
                Double score = embeddedDoc.getDouble("score");
                if(score < lowestHomework)
                {
                    lowestHomework = score;
                }
            }
        }
        Bson studentFilter = Filters.eq( "_id", doc.get("_id") );
        Bson delete = Updates.pull("scores", new Document("score", lowestHomework).append("type", "homework"));

        collection.updateOne(studentFilter, delete);
    }

    client.close();
}
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);
                        }
                    }
                }


            }


        }

    }
}

最好使用在過濾器中使用$pull的方法,以便僅從數組中刪除特定得分。 以下代碼使用帶模型API的MongoDB Java驅動程序v3.6。

import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
import static com.mongodb.client.model.Updates.pull;

public class RemoveLowestScoreArray {

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

            for (Document student : students) {
                Document lowestScore = null;
                for (Document score : (List<Document>) student.get("scores")) {
                    if (score.getString("type").equals("homework")) {
                        if (lowestScore == null || score.getDouble("score") < (lowestScore.getDouble("score"))) {
                            lowestScore = score;
                        }
                    }
                }
                collection.updateOne(student, pull("scores", lowestScore));
            }
        }
    }


}

您迭代數組並找到最低分數。 偽代碼:

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

我嘗試使用本機mongodb命令,該命令執行起來很簡單。 我嘗試給定的問題陳述進行了測試。使用下面的2條命令使其工作。

1)cursor = db.students.aggregate([[“” $ unwind“:” $ scores“},{” $ match“:{” scores.type“:”作業“}}},{” $ group“:{' _id':'$ _id','minitem':{'$ min':“ $ scores.score”}}}])),空

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

我嘗試使用MongoDB Java驅動程序的Aggregater類來解決此問題。 請參閱以下工作代碼以供參考。

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;
        }

這是我的方法,也許有人會覺得它更干凈,更容易理解:

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運算符從現有數組中刪除一個或多個與指定條件匹配的值的所有實例。

試試這個代碼:

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);

        }

我不知道它是否是最佳選擇,但可以:

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")))));

        }
    }
}

這是我解決此問題的方法。

    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)));
    }

我對上述問題的解決方案是:

    List<Document> results =
                        collection.aggregate(asList(
                                new Document("$unwind","$scores"),
                                new Document("$match", new Document("scores.type", new Document("$eq", "homework"))),
                                new Document("$group", new Document("_id", "$_id")
                                        .append("score", new Document("$min", "$scores.score")))))
                        .into(new ArrayList<Document>());
                for(Document doc : results)
                {
                    Integer id = doc.getInteger("_id");
                    Double score = doc.getDouble("score");
                    UpdateResult result = collection.updateOne(new Document("_id",new Document("$eq",id)), 
                            new Document("$pull", new Document("scores",
                                    new Document("score", score))));
                }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM