我有一份学生文件清单,其结构如下:
{
"_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();
}
}
答案 0 :(得分: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();
}
}
}
答案 1 :(得分: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));
}
答案 2 :(得分:2)
这里的所有答案都很棒。我只是想补充一下,如果有人想使用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();
}
答案 3 :(得分: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 :(得分:1)
最好使用带有过滤器的$pull
方法,以便从数组中删除特定分数。下面的代码使用MongoDB Java Driver v3.6和模型API。
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));
}
}
}
}
答案 5 :(得分: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
答案 6 :(得分:0)
我尝试使用原生的mongodb命令,这些命令很容易执行。我尝试了给定的问题陈述测试。使用以下2个命令使其工作。
1)cursor = db.students.aggregate([{“$ unwind”:“$ scores”},{“$ match”:{“scores.type”:“homework”}},{“$ group” :{'_ id':'$ _id','minitem':{'$ min':“$ scores.score”}}}]),null
2)cursor.forEach(function(coll){db.students.update({'_ id':coll._id},{'$ pull':{'scores':{'score':coll.minitem} }})})
答案 7 :(得分: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;
}
答案 8 :(得分:0)
这是我的方法,也许有人会发现它更清晰,更容易理解:
$pull
{% assign sum = 0 %}
{% for donation in signup.donation %}
{% if donation.succeeded_at | date: %s > 1483228801 %}
{% assign sum = sum | plus: donation %}
{% endif %}
{% endfor %}
{{ sum }}
运算符从现有数组中删除与指定条件匹配的值的所有实例。
答案 9 :(得分: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);
}
答案 10 :(得分: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")))));
}
}
}
答案 11 :(得分:0)
这是我解决此问题的方法。
PROPERTIES = list(set().union(*[n.properties for n in NETWORKS])) # random order
答案 12 :(得分:0)
我对上述问题的解决方案是:
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))));
}