2013-04-27 17 views
9

I eşleştirme alanları içten MongoDB

{ 
     "_id" : ObjectId("517b88decd483543a8bdd95b"), 
     "studentId" : 23, 
     "students" : [ 
      { 
      "id" : 23, 
      "class" : "a" 
      }, 
      { 
      "id" : 55, 
      "class" : "b" 
      } 
     ] 
    } 
    { 
     "_id" : ObjectId("517b9d05254e385a07fc4e71"), 
     "studentId" : 55, 
     "students" : [ 
      { 
      "id" : 33, 
      "class" : "c" 
      } 
     ] 
    } 

Note: değil gerçek veri ancak şema tam olarak aynı olan bir MongoDB

aşağıdaki belgeyi yaşıyorum.

Requirement:tek sorgu kullanarak öğrencilerin dizinin içindeki studentId ve students.id (id maçları belgeyi bulma.

Ben

db.data.aggregate({$match:{"students.id":"$studentId"}},{$group:{_id:"$student"}}); 

Result: Boş Array altında olursa gibi kod denedim ben {"students.id": "$ studentId"} yerine {"students.id" ifadesini kullanın: 33} ikinci belgeyi yukarıda gösterilen jsonda döndürüyor.

Tek bir sorgu kullanarak bu senaryonun belgelerini almak mümkün mü? Maalesef bu imkansız

cevap

13

Mümkünse, verileri saklarken durumunuzu ayarlamanızı öneririm, böylece hızlı bir doğruluk kontrolü yapabilirsiniz (isInStudentsList). Bu tür bir sorguyu yapmak çok hızlı olur. girişinizi örneğe göre

db.students.aggregate( 
    {$project: 
     {studentId: 1, studentIdComp: "$students.id"}}, 
    {$unwind: "$studentIdComp"}, 
    {$project : { studentId : 1, 
     isStudentEqual: { $eq : [ "$studentId", "$studentIdComp" ] }}}, 
    {$match: {isStudentEqual: true}}) 

çıkışı olacaktır:

{ 
    "result" : [ 
     { 
      "_id" : ObjectId("517b88decd483543a8bdd95b"), 
      "studentId" : 23, 
      "isStudentEqual" : true 
     } 
    ], 
    "ok" : 1 
} 

Aksi takdirde, tek bir sorguda istediğini yapmak Toplama çerçeve boru hattı kullanarak nispeten karmaşık bir yolu vardır adımların

açıklanması:

  1. sadeceile belgenin bir projeksiyon oluşturmave sadece id içeren bir dizi ile yeni bir alan (böylece ilk belge [23, 55] içerecektir.
  2. Bu yapıyı kullanarak, $unwind. Bu, studentIdComp dizisindeki her dizi öğesi için yeni bir geçici belge oluşturur.
  3. Şimdi, bu belgeleri alın ve studentId'a sahip olmaya devam eden yeni bir belge projeksiyonu oluşturun ve isStudentEqual adlı yeni alanı ekleyerek, studentId ve studentIdComp arasındaki iki alanın eşitliğini karşılaştırır. Bu noktada bu iki alanı içeren tek bir geçici belge olduğunu unutmayın.
  4. Son olarak, isStudentEqual karşılaştırma değerinin doğru olduğunu kontrol edin ve bu belgeleri (orijinal belge _id ve studentId içerecektir) döndürün.
  5. Öğrenci listede birkaç kez bulunuyorsa, sonuçları çoğaltmak için sonuçları studentId veya _id numaralı gruplarda gruplandırmanız gerekebilir (ancak bunun gerekeceğini bilmiyorum).
+0

İyi çalışıyor, açıklama için teşekkürler. +1 – karthick

-1

db.data.find({students: {$elemMatch: {id: 23}} , studentId: 23});

+0

ben soru koşulu (. Öğrencilerin liste studentId içeren belgeyi seçin) – WiredPrairie

0

(

o açıklamada (örnek nerede $ kullanmak gerekir bu sorunu çözmek için: Finding embeded document in mongodb?),

ama $ olduğu ,

0 numaralı ürünle kullanıldığında numaralı telefonu kısıtlamıştır
+0

@Asya sayesinde gerçek olduğu tüm belgeleri bulmak için nasıl olduğuna inanıyoruz;) –

+0

notu olsa Toplama çerçevesinde gerekli olmadığı durumlarda $ (olarak o WiredPrairie'nin cevabı, yeni bir alan oluşturmak için $ projesini kullanabileceğinizi ve daha sonra $ maçını kullanabildiğinizi gösterir. –

+0

tam olarak @ AsyaKamsky, ama birçok soruda, klasik durumu gözlemliyorum: bir hiyerarşide dosyalanmış ve başka bir alanı karşılaştır. Biliyorum, bu problem genellikle kötü bir veri modelinde. Pek çok dev veri depolama modeli oluşturmak sadece doğrudan ilişkisel depolardan kopyala + yapıştır;) –