MongoDB: come scoprire se un campo array contiene un elemento?

Ho due collezioni. La prima raccolta contiene studenti:

{ "_id" : ObjectId("51780f796ec4051a536015cf"), "name" : "John" } { "_id" : ObjectId("51780f796ec4051a536015d0"), "name" : "Sam" } { "_id" : ObjectId("51780f796ec4051a536015d1"), "name" : "Chris" } { "_id" : ObjectId("51780f796ec4051a536015d2"), "name" : "Joe" } 

La seconda raccolta contiene corsi:

 { "_id" : ObjectId("51780fb5c9c41825e3e21fc4"), "name" : "CS 101", "students" : [ ObjectId("51780f796ec4051a536015cf"), ObjectId("51780f796ec4051a536015d0"), ObjectId("51780f796ec4051a536015d2") ] } { "_id" : ObjectId("51780fb5c9c41825e3e21fc5"), "name" : "Literature", "students" : [ ObjectId("51780f796ec4051a536015d0"), ObjectId("51780f796ec4051a536015d0"), ObjectId("51780f796ec4051a536015d2") ] } { "_id" : ObjectId("51780fb5c9c41825e3e21fc6"), "name" : "Physics", "students" : [ ObjectId("51780f796ec4051a536015cf"), ObjectId("51780f796ec4051a536015d0") ] } 

Ogni documento del corso contiene una serie di students che ha una lista di studenti iscritti al corso. Quando uno studente visualizza un corso su una pagina web, deve vedere se è già iscritto al corso o no. Per fare ciò, quando la raccolta dei courses viene interrogata per conto dello studente, dobbiamo scoprire se l’array degli students contiene già l’ObjectId dello studente. C’è un modo per specificare nella proiezione di una query di ricerca per recuperare ObjectId students dall’array degli students solo se è lì?

Ho provato a vedere se potevo l’operatore $ elemMatch ma è orientato verso una serie di sotto-documenti. Capisco che potrei usare il framework di aggregazione ma sembra che sarebbe eccessivo in questo caso. Il framework di aggregazione probabilmente non sarà veloce quanto una singola query di ricerca. C’è un modo per interrogare la raccolta del corso in modo che il documento restituito possa essere in una forma simile a questa?

 { "_id" : ObjectId("51780fb5c9c41825e3e21fc4"), "name" : "CS 101", "students" : [ ObjectId("51780f796ec4051a536015d0"), ] } 

[ modifica basata su questo ora è ansible nelle versioni recenti]

[Risposta aggiornata] È ansible interrogare il seguente modo per ottenere il nome della class e l’id dello studente solo se sono già registrati.

 db.student.find({}, {_id:0, name:1, students:{$elemMatch:{$eq:ObjectId("51780f796ec4051a536015cf")}}}) 

e recupererai ciò che ti aspettavi:

 { "name" : "CS 101", "students" : [ ObjectId("51780f796ec4051a536015cf") ] } { "name" : "Literature" } { "name" : "Physics", "students" : [ ObjectId("51780f796ec4051a536015cf") ] } 

[Risposta originale] Non è ansible fare ciò che si vuole fare al momento. Questo è sfortunato perché sarebbe ansible farlo se lo studente fosse archiviato nell’array come object. In effetti, sono un po ‘sorpreso che tu stia usando ObjectId () in quanto ciò richiederà sempre che tu cerchi gli studenti se vuoi visualizzare un elenco di studenti iscritti ad un particolare corso (guarda la lista di Id prima e poi guarda i nomi nella raccolta studenti – due query invece di una!)

Se stavi memorizzando (ad esempio) un ID e un nome nell’array del corso in questo modo:

 { "_id" : ObjectId("51780fb5c9c41825e3e21fc6"), "name" : "Physics", "students" : [ {id: ObjectId("51780f796ec4051a536015cf"), name: "John"}, {id: ObjectId("51780f796ec4051a536015d0"), name: "Sam"} ] } 

La tua domanda quindi sarebbe semplicemente:

 db.course.find( { }, { students : { $elemMatch : { id : ObjectId("51780f796ec4051a536015d0"), name : "Sam" } } } ); 

Se lo studente fosse iscritto solo a CS 101 torneresti:

 { "name" : "Literature" } { "name" : "Physics" } { "name" : "CS 101", "students" : [ { "id" : ObjectId("51780f796ec4051a536015cf"), "name" : "John" } ] } 

Sembra che l’operatore $in soddisfi i tuoi scopi.

Potresti fare qualcosa del genere (pseudo-query):

 if (db.courses.find({"students" : {"$in" : [studentId]}, "course" : courseId }).count() > 0) { // student is enrolled in class } 

In alternativa, è ansible rimuovere il "course" : courseId clausola "course" : courseId e recuperare un set di tutte le classi in cui lo studente è iscritto.