MongoDB에서 수집 레코드 내부의 배열을 정렬하는 방법은 무엇입니까?
저는 다음과 같은 기록을 가진 학생들의 컬렉션을 가지고 있고 저는 분류하고 싶습니다.scores
의 배열score
.
몽고 껍질 위의 주문은 어떻게 생겼습니까?
> db.students.find({'_id': 1}).pretty()
{
"_id" : 1,
"name" : "Aurelia Menendez",
"scores" : [
{
"type" : "exam",
"score" : 60.06045071030959
},
{
"type" : "quiz",
"score" : 52.79790691903873
},
{
"type" : "homework",
"score" : 71.76133439165544
},
{
"type" : "homework",
"score" : 34.85718117893772
}
]
}
이 주문을 시도하고 있습니다.
doc = db.students.find()
for (_id,score) in doc.scores:
print _id,score
하지만 작동하지 않습니다.
응용 프로그램 코드에 포함된 배열을 조작하거나 MongoDB 2.2의 새로운 Aggregation Framework를 사용해야 합니다.
예mongo
개요:
db.students.aggregate(
// Initial document match (uses index, if a suitable one is available)
{ $match: {
_id : 1
}},
// Expand the scores array into a stream of documents
{ $unwind: '$scores' },
// Filter to 'homework' scores
{ $match: {
'scores.type': 'homework'
}},
// Sort in descending order
{ $sort: {
'scores.score': -1
}}
)
샘플 출력:
{
"result" : [
{
"_id" : 1,
"name" : "Aurelia Menendez",
"scores" : {
"type" : "homework",
"score" : 71.76133439165544
}
},
{
"_id" : 1,
"name" : "Aurelia Menendez",
"scores" : {
"type" : "homework",
"score" : 34.85718117893772
}
}
],
"ok" : 1
}
에서 시작Mongo 5.2
새로운 집계 연산자의 정확한 사용 사례입니다.
// {
// name: "Aurelia Menendez",
// scores: [
// { type: "exam", score: 60.06 }
// { type: "quiz", score: 52.79 }
// { type: "homework", score: 71.76 }
// { type: "homework", score: 34.85 }
// ]
// }
db.collection.aggregate([
{ $set: {
scores: {
$sortArray: {
input: "$scores",
sortBy: { score: -1 }
}
}
}}
])
// {
// name: "Aurelia Menendez",
// scores: [
// { type: "homework", score: 71.76 },
// { type: "exam", score: 60.06 },
// { type: "quiz", score: 52.79 },
// { type: "homework", score: 34.85 }
// ]
// }
다음 항목:
- 소트)
$sortArray
그scores
열배)input: "$scores"
) - 에 정렬을 적용함으로써.
score
s(s)sortBy: { score: -1 }
) - 고가의 조합을 적용할 필요 없이
$unwind
,$sort
그리고.$group
이 질문은 다양한 방법으로 관리할 수 있기 때문에 다른 솔루션으로는 "삽입 및 정렬"이 있습니다. 이렇게 하면 찾기()를 수행하는 순간 주문된 배열을 얻을 수 있습니다.
이 데이터를 고려해 보십시오.
{
"_id" : 5,
"quizzes" : [
{ "wk": 1, "score" : 10 },
{ "wk": 2, "score" : 8 },
{ "wk": 3, "score" : 5 },
{ "wk": 4, "score" : 6 }
]
}
여기서 문서를 업데이트하고 정렬합니다.
db.students.update(
{ _id: 5 },
{
$push: {
quizzes: {
$each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
$sort: { score: -1 },
$slice: 3 // keep the first 3 values
}
}
}
)
결과:
{
"_id" : 5,
"quizzes" : [
{ "wk" : 1, "score" : 10 },
{ "wk" : 2, "score" : 8 },
{ "wk" : 5, "score" : 8 }
]
}
설명서: https://docs.mongodb.com/manual/reference/operator/update/sort/ #up._S_sort
JS와 mongo 콘솔을 통해 이 문제를 해결할 수 있었습니다.
db.students.find({"scores.type": "homework"}).forEach(
function(s){
var sortedScores = s.scores.sort(
function(a, b){
return a.score<b.score && a.type=="homework";
}
);
var lowestHomeworkScore = sortedScores[sortedScores.length-1].score;
db.students.update({_id: s._id},{$pull: {scores: {score: lowestHomeworkScore}}}, {multi: true});
})
배열을 정렬하려면 다음 단계를 수행합니다.
unwind를 사용하여 배열을 반복합니다.
정렬 배열
그룹을 사용하여 어레이 개체를 하나의 어레이로 병합
그런 다음 다른 필드를 투영합니다.
쿼리
db.taskDetails.aggregate([
{$unwind:"$counter_offer"},
{$match:{_id:ObjectId('5bfbc0f9ac2a73278459efc1')}},
{$sort:{"counter_offer.Counter_offer_Amount":1}},
{$unwind:"$counter_offer"},
{"$group" : {_id:"$_id",
counter_offer:{ $push: "$counter_offer" },
"task_name": { "$first": "$task_name"},
"task_status": { "$first": "$task_status"},
"task_location": { "$first": "$task_location"},
}}
]).pretty()
여기 배열에서 가장 낮은 점수를 찾아 제거하는 데 사용할 수 있는 Java 코드가 있습니다.
public class sortArrayInsideDocument{
public static void main(String[] args) throws UnknownHostException {
MongoClient client = new MongoClient();
DB db = client.getDB("school");
DBCollection lines = db.getCollection("students");
DBCursor cursor = lines.find();
try {
while (cursor.hasNext()) {
DBObject cur = cursor.next();
BasicDBList dbObjectList = (BasicDBList) cur.get("scores");
Double lowestScore = new Double(0);
BasicDBObject dbObject = null;
for (Object doc : dbObjectList) {
BasicDBObject basicDBObject = (BasicDBObject) doc;
if (basicDBObject.get("type").equals("homework")) {
Double latestScore = (Double) basicDBObject
.get("score");
if (lowestScore.compareTo(Double.valueOf(0)) == 0) {
lowestScore = latestScore;
dbObject = basicDBObject;
} else if (lowestScore.compareTo(latestScore) > 0) {
lowestScore = latestScore;
dbObject = basicDBObject;
}
}
}
// remove the lowest score here.
System.out.println("object to be removed : " + dbObject + ":"
+ dbObjectList.remove(dbObject));
// update the collection
lines.update(new BasicDBObject("_id", cur.get("_id")), cur,
true, false);
}
} finally {
cursor.close();
}
}
}
충분히 쉽게 추측할 수 있지만, 어쨌든, 몽고 대학 과정을 가지고 부정행위를 하지 마세요. 왜냐하면 여러분은 그때 기본적인 것을 이해하지 못할 것이기 때문입니다.
db.students.find({}).forEach(function(student){
var minHomeworkScore,
scoresObjects = student.scores,
homeworkArray = scoresObjects.map(
function(obj){
return obj.score;
}
);
minHomeworkScore = Math.min.apply(Math, homeworkArray);
scoresObjects.forEach(function(scoreObject){
if(scoreObject.score === minHomeworkScore){
scoresObjects.splice(scoresObjects.indexOf(minHomeworkScore), 1);
}
});
printjson(scoresObjects);
});
제목과 배열 제목도 주문하고 전체 컬렉션 데이터를 반환합니다. 컬렉션 이름은 메뉴
[
{
"_id": "5f27c5132160a22f005fd50d",
"title": "Gift By Category",
"children": [
{
"title": "Ethnic Gift Items",
"s": "/gift?by=Category&name=Ethnic"
},
{
"title": "Novelty Gift Items",
"link": "/gift?by=Category&name=Novelty"
}
],
"active": true
},
{
"_id": "5f2752fc2160a22f005fd50b",
"title": "Gift By Occasion",
"children": [
{
"title": "Gifts for Diwali",
"link": "/gift-for-diwali"
},
{
"title": "Gifts for Ganesh Chathurthi",
"link": "/gift-for-ganesh-chaturthi",
}
],
"active": true
}
]
아래와 같이 문의합니다.
let menuList = await Menu.aggregate([
{
$unwind: '$children'
},
{
$sort:{"children.title":1}
},
{
$group : { _id : "$_id",
root: { $mergeObjects: '$$ROOT' },
children: { $push: "$children" }
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: ['$root', '$$ROOT']
}
}
},
{
$project: {
root: 0
}
},
{
$match: {
$and:[{'active':true}],
}
},
{
$sort:{"title":1}
}
]);
나는 당신이 하고 있다고 믿습니다.M101P: MongoDB for Developers
여기서 숙제 3.1은 두개의 숙제 점수에서 낮은 것을 제거하는 것입니다.이때까지 집계가 학습되지 않았기 때문에 다음과 같은 작업을 수행할 수 있습니다.
import pymongo
conn = pymongo.MongoClient('mongodb://localhost:27017')
db = conn.school
students = db.students
for student_data in students.find():
smaller_homework_score_seq = None
smaller_homework_score_val = None
for score_seq, score_data in enumerate(student_data['scores']):
if score_data['type'] == 'homework':
if smaller_homework_score_seq is None or smaller_homework_score_val > score_data['score']:
smaller_homework_score_seq = score_seq
smaller_homework_score_val = score_data['score']
students.update({'_id': student_data['_id']}, {'$pop': {'scores': smaller_homework_score_seq}})
다음은 MongoDB에 대한 PyMongo 드라이버인 pyMongo를 사용하는 제 접근 방식입니다.
import pymongo
conn = pymongo.MongoClient('mongodb://localhost')
def remove_lowest_hw():
db = conn.school
students = db.students
# first sort scores in ascending order
students.update_many({}, {'$push':{'scores':{'$each':[], '$sort':{'score': 1}}}})
# then collect the lowest homework score for each student via projection
cursor = students.find({}, {'scores':{'$elemMatch':{'type':'homework'}}})
# iterate over each student, trimming each of the lowest homework score
for stu in cursor:
students.update({'_id':stu['_id']}, {'$pull':{'scores':{'score':stu['scores'][0]['score']}}})
remove_lowest_hw()
conn.close()
이 일은 저에게 약간의 거친 코드이지만 학생 개개인의 가장 낮은 과제의 결과는 정확합니다.
var scores_homework = []
db.students.find({"scores.type": "homework"}).forEach(
function(s){
s.scores.forEach(
function(ss){
if(ss.type=="homework"){
ss.student_id = s._id
scores_homework.push(ss)
}
}
)
})
for(i = 0; i < scores_homework.length; i++)
{
var b = i+1;
var ss1 = scores_homework[i];
var ss2 = scores_homework[b];
var lowest_score = {};
if(ss1.score > ss2.score){
lowest_score.type = ss2.type;
lowest_score.score = ss2.score;
db.students.update({_id: ss2.student_id},{$pull: {scores: {score: lowest_score.score}}});
}else if(ss1.score < ss2.score){
lowest_score.type = ss1.type;
lowest_score.score = ss1.score;
db.students.update({_id: ss1.student_id},{$pull: {scores: {score: lowest_score.score}}});
}else{
lowest_score.type = ss1.type;
lowest_score.score = ss1.score;
db.students.update({_id: ss1.student_id},{$pull: {scores: {score: lowest_score.score}}});
}
i++
}
이것이 제가 자바에서 구현한 방법입니다 (이해하기 쉽게 단순하게 유지) -
접근 방식:
- 학생 모음에서 점수 배열 가져오기
- == 숙제 유형의 점수 배열에서 모든 점수 값 가져오기
- 가장 낮은 값이 첫 번째 요소가 되도록 점수 값을 정렬합니다 [score.get(0)].
- 그런 다음, == 숙제 & & 점수 == 점수.get(0) 유형의 요소를 건너뛰면서 주 점수를 반복하고 점수 배열의 새 사본을 만듭니다.
- 마지막으로 새 점수 배열을 학생 문서로 업데이트합니다.
다음은 작동 중인 Java 코드입니다.
public void removeLowestScore(){
//Create mongo client and database connection and get collection
MongoClient client = new MongoClient("localhost");
MongoDatabase database = client.getDatabase("school");
MongoCollection<Document> collection = database.getCollection("students");
FindIterable<Document> docs = collection.find();
for (Document document : docs) {
//Get scores array
ArrayList<Document> scores = document.get("scores", ArrayList.class);
//Create a list of scores where type = homework
List<Double> homeworkScores = new ArrayList<Double>();
for (Document score : scores) {
if(score.getString("type").equalsIgnoreCase("homework")){
homeworkScores.add(score.getDouble("score"));
}
}
//sort homework scores
Collections.sort(homeworkScores);
//Create a new list to update into student collection
List<Document> newScoresArray = new ArrayList<Document>();
Document scoreDoc = null;
//Below loop populates new score array with eliminating lowest score of "type" = "homework"
for (Document score : scores) {
if(score.getString("type").equalsIgnoreCase("homework") && homeworkScores.get(0) == score.getDouble("score")){
continue;
}else{
scoreDoc = new Document("type",score.getString("type"));
scoreDoc.append("score",score.getDouble("score"));
newScoresArray.add(scoreDoc);
}
}
//Update the scores array for every student using student _id
collection.updateOne(Filters.eq("_id", document.getInteger("_id")), new Document("$set",new Document("scores",newScoresArray)));
}
}
확실히 늦었지만, 저는 Mongo Shell에 대한 저만의 해결책을 제공하고 싶습니다.
var students = db.getCollection('students').find({});
for(i = 0 ; i < students.length(); i++) {
var scores = students[i].scores;
var tmp = [];
var min = -1 ;
var valueTmp = {};
for(j = 0 ; j < scores.length; j++) {
if(scores[j].type != 'homework') {
tmp.push(scores[j]);
} else {
if (min == -1) {
min = scores[j].score;
valueTmp = scores[j];
} else {
if (min > scores[j].score) {
min = scores[j].score;
tmp.push(valueTmp);
valueTmp = scores[j];
} else {
tmp.push(scores[j]);
}
}
}
}
db.students.updateOne({_id:students[i]._id},
{$set:{scores:tmp}});
}
@Stennie의 대답은 괜찮습니다, 아마도.$group
연산자는 많은 문서에서 (점수별로 하나씩) 폭발시키지 않고 원본 문서를 보관하는 데 유용합니다.
저는 당신의 애플리케이션에 자바스크립트를 사용할 때 다른 솔루션을 추가할 뿐입니다.
하나의 문서만 쿼리하는 경우 집계 대신 JS별로 내장된 배열을 정렬하는 것이 더 쉬운 경우가 있습니다.문서에 필드가 많을 경우 사용하는 것보다 훨씬 좋습니다.$push
연산자, 그렇지 않으면 모든 필드를 하나씩 밀어넣어야 합니다.$$ROOT
연산자(내가 틀렸습니까?)
내 예제 코드는 Mongoose.js를 사용합니다: 학생 모델을 초기화했다고 가정합니다.
// Sorting
function compare(a, b) {
return a.score - b.score;
}
Students.findById('1', function(err, foundDocument){
foundDocument.scores = foundDocument.scores.sort(compare);
// do what you want here...
// foundModel keeps all its fields
});
점수에 따른 정렬은 다음과 같이 간단할 수 있습니다.
db.students.find({_id:137}).sort({score:-1}).pretty()
하지만 당신은 유형에 맞는 것을 찾아야 해요. 바로 그것입니다.
다음과 같은 것이어야 합니다.
db.students.find().sort(scores: ({"score":-1}));
언급URL : https://stackoverflow.com/questions/13449874/how-to-sort-array-inside-collection-record-in-mongodb
'programing' 카테고리의 다른 글
PostgreSQL에서 데이터 항목이 자동으로 삭제되는 "만료" 시간을 설정하는 방법이 있습니까? (0) | 2023.05.29 |
---|---|
두 개의 완전히 독립된 Eclipse 인스턴스를 동시에 실행할 수 있습니까? (0) | 2023.05.29 |
모서리 반지름 설정 버튼 템플릿 (0) | 2023.05.29 |
mongo 스크립트로 파일 쓰기 작업을 수행하시겠습니까? (0) | 2023.05.29 |
IEnumberable에 두 개 이상의 요소가 있는지 효율적으로 확인하려면 어떻게 해야 합니까? (0) | 2023.05.29 |