私は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:最初にtype:homeworksですべてのドキュメントをフィルタリングします
2:student_idで並べ替え、スコア
3:student_idでグループを作成し、最初の要素を見つけます
これにより、スコアが最も低いすべてのドキュメントが得られます。
ただし、元のデータセットからこれらの要素を削除するにはどうすればよいですか?ガイダンスやヒントはありますか?
集計からのカーソル結果を使用して、カーソルの forEach()
メソッドでドキュメントをループし、_id
を使用してコレクションから各ドキュメントを削除します。 remove()
メソッドのクエリ。このようなもの:
var cursor = db.grades.aggregate(pipeline);
cursor.forEach(function (doc){
db.grades.remove({"_id": doc._id});
});
別のアプローチは、 map()
メソッドを使用してドキュメントの_id
sの配列を作成し、次のようにドキュメントを削除することです。
var cursor = db.grades.aggregate(pipeline),
ids = cursor.map(function (doc) { return doc._id; });
db.grades.remove({"_id": { "$in": ids }});
-[〜#〜] update [〜#〜]-
大規模な削除操作の場合は、保持するドキュメントを新しいコレクションにコピーしてから、 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()
でクエリを実行できます。
これは、MongoDBの宿題のデータベース部分だと思いますJava MongoDB大学が提供する開発者。個々の学生から最低スコアを削除する必要があります。とにかく、私はこの方法で解決しました。それがあなたに役立つことを願っています。私の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 アカウントには、完全なプロジェクトコードがあります。誰かが欲しいなら、これから試すことができます リンク 。
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})
})
Mongo 4.4
から、$group
ステージに新しい集計演算子が追加されました $accumulator
グループ化されたドキュメントのカスタム累積が可能になります。
$out
ステージと組み合わせて、この場合、元のコレクションを集計パイプラインの結果(学生ごとの最低スコアから削除されたもの)に置き換えるために使用されます。
// > db.collection.find()
// { "student_id" : 0, "type" : "exam", "score" : 54.6535436362647 }
// { "student_id" : 0, "type" : "homework", "score" : 14.8504576811645 }
// { "student_id" : 0, "type" : "homework", "score" : 63.98402553675503 }
// { "student_id" : 1, "type" : "homework", "score" : 21.33260810416115 }
// { "student_id" : 1, "type" : "homework", "score" : 44.31667452616328 }
db.collection.aggregate(
{ $group: {
_id: "$student_id",
docs: { $accumulator: {
accumulateArgs: ["$$ROOT"],
init: function() { return []; },
accumulate: function(docs, doc) { return docs.concat(doc); },
merge: function(docs1, docs2) { return docs1.concat(docs2); },
finalize: function(docs) {
var min = Math.min(...docs.map(x => x.score));
var i = docs.findIndex((doc) => doc.score == min);
docs.splice(i, 1);
return docs;
},
lang: "js"
}}
}},
{ $unwind: "$docs" },
{ $replaceWith: "$docs" },
{ $out: "collection" }
)
// > db.collection.find()
// { "student_id" : 0, "type" : "exam", "score" : 54.6535436362647 }
// { "student_id" : 0, "type" : "homework", "score" : 63.98402553675503 }
// { "student_id" : 1, "type" : "homework", "score" : 44.31667452616328 }
この:
$group
sドキュメントをstudent_id
で作成し、スコアが最も低いドキュメントから削除された配列としてそれらを累積します。
accumulateArgs
は、累積関数で使用されるフィールド(またはこの場合はドキュメント全体 $$ROOT
)の組み合わせです。
元の累積配列はそれぞれ、空の配列としてinit
ializedされます。
ドキュメントは単にconcat
anated(accumulate
およびmerge
)です。
最後に、すべてのドキュメントがグループ化されると、finalize
ステップで、スコアが最も低いグループ化されたドキュメントを見つけて削除できます。
この段階の終わりに、パイプライン化されたドキュメントは次のようになります。
{
"_id" : 0,
"docs" : [
{ "student_id" : 0, "type" : "exam", "score" : 54.6535436362647 },
{ "student_id" : 0, "type" : "quiz", "score" : 31.95004496742112 },
{ "student_id" : 0, "type" : "homework", "score" : 63.98402553675503 }
]
}
...
$unwind
sグループ化されたドキュメントの累積フィールド。グループ化されたドキュメントの配列をフラット化し、次のようなものに戻ります。
{ "_id" : 0, "docs" : { "student_id" : 0, "type" : "exam", "score" : 54.6535436362647 } }
{ "_id" : 0, "docs" : { "student_id" : 0, "type" : "quiz", "score" : 31.95004496742112 } }
{ "_id" : 0, "docs" : { "student_id" : 0, "type" : "homework", "score" : 63.98402553675503 } }
...
$replaceWith
元の形式を見つけるために、累積されたフィールドの内容を含む各ドキュメントのすべての既存のフィールド。この段階の終わりには、次のようなものがあります。
{ "student_id" : 0, "type" : "exam", "score" : 54.6535436362647 }
{ "student_id" : 0, "type" : "quiz", "score" : 31.95004496742112 }
{ "student_id" : 0, "type" : "homework", "score" : 63.98402553675503 }
...
$out
集約パイプラインの結果を同じコレクションに挿入します。 $out
は、指定されたコレクションのコンテンツを便利に置き換えるため、このソリューションが可能になることに注意してください。
int studentId =(int)doc.get( "student_id");
変換タイプエラーが発生します。もう一度確認できますか?
私が知っているように、私たちは以下のように作ることができます。
int studentId = Integer.valueOf(doc.get( "student_id")。toString());
この質問は、MongoDB大学によるM101P:MongoDB forDevelopersコースの一部です。ここでの要件は次のとおりです。-
データセットから、各学生のスコアが最も低いタイプ「宿題」の成績を削除します。各ドキュメントは1つの学年であるため、生徒ごとに1つのドキュメントを削除する必要があります。
つまり、すべてのstudent_idから4つの「タイプ」が存在し、そのうち2つの「タイプ」は「宿題」です。 2つの「タイプ」:「宿題」ドキュメントから最低スコアを削除する必要があります。
Pymongoの稼働中のコードは以下のとおりです:-
import pymongo
import sys
//establish a connection to database
connection=pymongo.MongoClient('localhost',27017)
//Get a handle to students database
db=connection.students
mycol=db.grades
def remove_documents():
pipe=[
{'$match':{'type':'homework'}},
{'$group':{'_id':'$student_id','minscore': {'$min':'$score'}}}
,{'$sort':{'_id':1}}
]
result_cursor=mycol.aggregate(pipeline=pipe)
counter=0
for i in result_cursor:
query={'student_id':i['_id'],'score':i['minscore']}
del_record=mycol.delete_one(query)
if (int(del_record.deleted_count) > 0):
counter+=1
else:
continue
print(counter)
remove_documents()
ターミナル出力:-$ python remove_grade.py
200