come ordinare l’array all’interno del record di raccolta in mongoDB

MongoDB noob qui …

Ok, ho una collezione di studenti, ognuno con un record che assomiglia al seguente …. Voglio ordinare i punteggi del tipo: “compiti a casa” in ordine decrescente.

che aspetto ha questo incantesimo sul guscio dei mongo?

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

Sto provando questo incantesimo ….

  doc = db.students.find() for (_id,score) in doc.scores: print _id,score 

ma non funziona

Dovrai manipolare l’array incorporato nel codice dell’applicazione o utilizzare il nuovo framework di aggregazione in MongoDB 2.2.

Esempio di aggregazione nella shell 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 }} ) 

Uscita di esempio:

 { "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 } 

Ecco come abbiamo potuto risolvere questo problema con JS e la console mongo:

 db.students.find({"scores.type": "homework"}).forEach( function(s){ var sortedScores = s.scores.sort( function(a, b){ return a.score 

Ecco il codice java che può essere usato per scoprire il punteggio più basso dell’array e rimuoverlo.

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

È abbastanza facile da indovinare, ma in ogni caso, cerca di non imbrogliare con i corsi universitari di mongo perché non capirai le basi allora.

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

Credo che tu stia facendo M101P: MongoDB for Developers cui i compiti 3.1 sono di rimuovere quello inferiore da due punteggi per i compiti a casa. Poiché le aggregazioni non sono state insegnate fino a quel punto, puoi fare qualcosa del genere:

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

Poiché questa domanda può essere gestita in diversi modi, voglio dire che un’altra soluzione è “inserisci e ordina”, in questo modo otterrai l’array Ordinato nel momento in cui creerai un Trova ().

Considera questi dati:

 { "_id" : 5, "quizzes" : [ { "wk": 1, "score" : 10 }, { "wk": 2, "score" : 8 }, { "wk": 3, "score" : 5 }, { "wk": 4, "score" : 6 } ] } 

Qui aggiorneremo il documento, facciamo l’ordinamento.

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

Il risultato è:

 { "_id" : 5, "quizzes" : [ { "wk" : 1, "score" : 10 }, { "wk" : 2, "score" : 8 }, { "wk" : 5, "score" : 8 } ] } 

Documentazione: https://docs.mongodb.com/manual/reference/operator/update/sort/#up._S_sort

la risposta di @Stennie va bene, forse un operatore di $ group sarebbe utile per mantenere il documento originale, senza esploderlo in molti documenti (uno per punteggio).

Ho appena aggiunto un’altra soluzione quando si utilizza javascript per la tua applicazione .

se si esegue una query solo su un documento, a volte è più semplice ordinare l’array incorporato da JS, anziché eseguire un aggregato. Quando il tuo documento ha molti campi, è persino meglio che usare l’operatore $ push, altrimenti devi spingere tutti i campi uno per uno, o usare l’operatore $$ ROOT (mi sbaglio?)

Il mio codice di esempio utilizza Mongoose.js : Supponi di aver inizializzato il modello Studenti.

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

questo lavoro per me, è un po ‘di codice approssimativo, ma i risultati dei compiti più bassi per ogni studente sono corretti.

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

Questo è il mio approccio usando pyMongo, il driver Python per MongoDB:

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

Ecco come ho implementato in Java (averlo tenuto semplice in modo che sia più facile da capire) –

Approccio :

  1. Ottieni serie di punteggi dalla collezione di studenti
  2. Ottieni tutti i valori del punteggio dall’array dei punteggi dove scrivi == i compiti
  3. Ordina i valori del punteggio in modo che il più basso diventi 1 ° elemento [punteggio.get (0)]
  4. Quindi, passa attraverso i punteggi principali e crea una nuova copia della matrice dei punteggi mentre salta gli elementi dove scrivi == compiti a casa && score == scores.get (0)
  5. Infine, aggiorna la nuova serie di punteggi al documento dello studente.

Di seguito è riportato il codice Java funzionante:

  public void removeLowestScore(){ //Create mongo client and database connection and get collection MongoClient client = new MongoClient("localhost"); MongoDatabase database = client.getDatabase("school"); MongoCollection collection = database.getCollection("students"); FindIterable docs = collection.find(); for (Document document : docs) { //Get scores array ArrayList scores = document.get("scores", ArrayList.class); //Create a list of scores where type = homework List homeworkScores = new ArrayList(); 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 newScoresArray = new ArrayList(); 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))); } } 

Certamente è tardi, ma voglio solo contribuire con la mia soluzione su 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}}); } 

ordinare per punteggio può essere semplice come:

 db.students.find({_id:137}).sort({score:-1}).pretty() 

ma devi trovare quello per tipo: compiti a casa …

dovrebbe essere qualcosa del genere:

 db.students.find().sort(scores: ({"score":-1}));