2016-04-06 21 views
2

Ben MongoDB için yeni ve bunun üzerine bazı egzersizleri yapıyorum n'inci Belgesi üzerindeki Maç için. Belge "Restaurant" için aşağıdaki yapı göz önüne alındığındaSorgu bir Array

:

{ 
     "_id" : ObjectId("5704adbc2eb7ebe23f582818"), 
     "address" : { 
       "building" : "1007", 
       "coord" : [ 
         -73.856077, 
         40.848447 
       ], 
       "street" : "Morris Park Ave", 
       "zipcode" : "10462" 
     }, 
     "borough" : "Bronx", 
     "cuisine" : "Bakery", 
     "grades" : [ 
       { 
         "date" : ISODate("2014-03-03T00:00:00Z"), 
         "grade" : "A", 
         "score" : 2 
       }, 
       { 
         "date" : ISODate("2013-09-11T00:00:00Z"), 
         "grade" : "A", 
         "score" : 6 
       }, 
       { 
         "date" : ISODate("2013-01-24T00:00:00Z"), 
         "grade" : "A", 
         "score" : 10 
       }, 
       { 
         "date" : ISODate("2011-11-23T00:00:00Z"), 
         "grade" : "A", 
         "score" : 9 
       }, 
       { 
         "date" : ISODate("2011-03-10T00:00:00Z"), 
         "grade" : "B", 
         "score" : 14 
       } 
     ], 
     "name" : "Morris Park Bake Shop", 
     "restaurant_id" : "30075445" 
} 

restoran Kimliği, isim bulmak için bir MongoDB sorgusu yazın Özellikle ben hangi burada soru rapor, this exercise üzerinde saplanıp ve 2. dereceden oluşan dizinin bir "A" derecesi ve bir ISODate "2014-08-11T00: 00: 00Z" de 9 puanını aldığı restoranlar için notlar.

db.restaurants.find(
{ 
    'grades.1': { 
     'score': 'A', 
     'grade': 9, 
     'date' : ISODate("2014-08-11T00:00:00Z") 
    } 
}, 
{ 
    restaurant_id: 1, 
    name: 1, 
    grades: 1 
}); 

çalışmıyor:

ben bu sorguyu yazdım.
db.restaurants.find( 
    { "grades.1.date": ISODate("2014-08-11T00:00:00Z"), 
     "grades.1.grade":"A" , 
     "grades.1.score" : 9 
    }, 
    {"restaurant_id" : 1,"name":1,"grades":1} 
); 

Benim sorulara

şunlardır:

  1. grades.1 bölümünü tekrarlamak kaçınarak sorguyu yazmak için bir yol yoktur sağlanan çözüm şudur?
  2. neden yanlış benim sorgu, grades.1 bir belge nesne olduğunu verilir? Benim soruya cevap yardımcı olabilir

, ben MongoDB shell version: 3.2.4

DÜZENLEMEYİ kullanıyorum:

Ben this question 2 sayesinde sorgulamaya cevabını buldum.

Özellikle ben sipariş önemli olduğunu keşfetti. Aşağıdaki sorguyu gerçekleştirirseniz Nitekim, ben geçerli bir sonuç almak: Bu sorgu çalışır

db.restaurants.find({'grades.1': {'date': ISODate("2014-08-11T00:00:00Z"), 'grade':'A', score:9}}, {restaurant_id:1, name:1, grades:1}) 

Not sadece çünkü tüm alt belge yönettiği "alanlar" belirtilir ve bunlar aynı sırayla belirtilmiştir.

+1

Geçerli bir belge değil çünkü alan adları '$' – styvane

+0

ile başlayamıyor Bu doğru bir yanlış yapı sağladı. Bunu gerçek bir – user2340612

+0

ile düzelttim Sorgulama kriterlerinizde de göründüğünden, geçerli bir 'date' kullanmalısınız. – styvane

cevap

2

Aslında değil. Ama "yapabildiğini" belki de ne bir açıklama:

db.junk.find({ 
    "grades": { 
     "$elemMatch": { 
     "date" : ISODate("2014-03-03T00:00:00Z"), 
     "grade" : "A", 
     "score" : 2 
     } 
    }, 
    "$where": function() { 
     var grade = this.grades[0]; 
     return (
     grade.date.valueOf() == ISODate("2014-03-03T00:00:00Z").valueOf() && 
     grade.grade === "A" && 
     grade.score ==== 2 
    ) 
    } 
    }) 

$elemMatch biraz kısaltmak için izin verir, ama bu dizinin "inci" öğesi değil. o daha da daraltmak amacıyla tüm değerler bir eşleşme olup olmadığını görmek için "n'inci" dizi elemanı incelemek için $where maddesini kullanmak gerekir.

db.junk.aggregate([ 
    { "$match": { 
     "grades": { 
     "$elemMatch": { 
      "date" : ISODate("2014-03-03T00:00:00Z"), 
      "grade" : "A", 
      "score" : 2 
     } 
     } 
    }}, 
    { "$redact": { 
     "$cond": { 
     "if": { 
      "$let": { 
      "vars": { "grade": { "$arrayElemAt": [ "$grades", 0 ] } }, 
      "in": { 
       "$and": [ 
       { "$eq": [ "$grade.date", ISODate("2014-03-03T00:00:00Z") ] }, 
       { "$eq": [ "$grade.grade", "A" ] }, 
       { "$eq": [ "$grade.score", 2 ] } 
       ] 
      } 
      } 
     }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
     } 
    }} 
    ]) 

Sen $redact yanı .aggregate() kullanarak aynı mantık yapabilirsiniz. Biraz daha hızlı çalışır, ancak temel gerçek şu ana kadar açık olmalıdır. Zaten bunu yazmak için en verimli ve "kısa" bir yol olduğunu yapmış gibi

Yani dizi içindeki her bir elemanı için "n'inci" pozisyonunu belirlemek için "dot notation" kullanarak. Daha kısa veya daha iyi yapamazsın.

Diğer girişiminiz, "grades.1" içinde "belge" araması yapmakta olup, ile tam olarak eşleşen belgelerini karşılamaktadır. Herhangi bir nedenle, yalnızca alanları mevcut değilse veya saklanan belgede gerçekten "farklı düzen" durumundalarsa, gibi bir sorgu koşulu eşleşmeyecektir.

+0

Teşekkürler! “Gereksiz” tekrarları tekrar etmekten (ya da en azından, gereksiz olduğunu düşündüğümden) kaçınmak için bir kaç yol arıyordum. Maalesef, karakterleri kaydetmek için tüm şartları tekrarlamam gerekiyor gibi görünüyor :) Bu özel durumda, ancak, benim soruma eklediğim sorguyu kullanarak birkaç karakter kaydedebiliyorum. DÜZENLEME: Düzenlemenizi cevaba az önce gördüm! – user2340612

+1

@ user2340612 "Nokta gösterimi" yöntemi, kısalık ve verimlilik açısından en iyisidir. Eğer bir şekilde "notları" yapabilirseniz "güzel" olur: {"$ elemMatch": {...}} ', ama tabi ki, eleman zaten bir" Nesne "olarak" ertelenir ". bu noktayla beraber. Hem "$ elemMatch" hem de "dot notation", "tam eşleşme" problemiyle mücadele etmek için var. –

+0

Evet, "notlar.0" gibi bir çözüm: {"$ elemMatch": {...}}, "nokta notasyonu" nun avantajları ile ("tam eşleme" problemi) ve Bu durumda "tam eşleşme" gösterimi harika olurdu – user2340612