2017-02-08 29 views
12

Ben yeni çıkıyorum. Fakat sorguları yazmanın en mantıklı yollarını öğrenmeye çalışıyorum.2 farklı alanda arama değeri mongodb + node.js

Şu şekilde olan koleksiyonum var;

{ 
    "id" : NumberInt(1), 
    "school" : [ 
     { 
      "name" : "george", 
      "code" : "01" 
     }, 
     { 
      "name" : "michelangelo", 
      "code" : "01" 
     } 
    ], 
    "enrolledStudents" : [ 
     { 
      "userName" : "elisabeth", 
      "code" : NumberInt(21) 
     } 
    ] 
} 
{ 
    "id" : NumberInt(2), 
    "school" : [ 
     { 
      "name" : "leonarda da vinci", 
      "code" : "01" 
     } 
    ], 
    "enrolledStudents" : [ 
     { 
      "userName" : "michelangelo", 
      "code" : NumberInt(25) 
     } 
    ] 
} 

Ben onların code değerleri karşılık gelen bir key oluşumunu listelemek istiyorum. Bir örnek key olarak

: michelangelo

Ben iki ayırıcı aggregation sorguları yazdım, anahtarın oluşumunu bulmak için;

db.test.aggregate([ 
    {$unwind: "$school"}, 
    {$match : {"school.name" : "michelangelo"}}, 
    {$project: {_id: "$id", "key" : "$school.name", "code" : "$school.code"}} 
]) 

ve bu 2 sorguları

db.test.aggregate([ 
    {$unwind: "$enrolledStudents"}, 
    {$match : {"enrolledStudents.userName" : "michelangelo"}}, 
    {$project: {_id: "$id", "key" : "$enrolledStudents.userName", "code" : "$enrolledStudents.code"}} 
]) 

sonuç Ben istediğim dönmek; Bunlardan

{ "_id" : 1, "key" : "michelangelo", "code" : "01" } 
{ "_id" : 2, "key" : "michelangelo", "code" : 25 } 

Bir diğeri school alanda aradığı, enrolledStudents arama yapmak için.

Bu 2 sorgu daha mantıklı bir sorguya indirgenebilir mi? Yoksa bunu yapmanın tek yolu bu mu?

ps: Veritabanının yapısının mantıklı olmadığını biliyorum, ancak benzetmeye çalıştım.

düzenleme Bulmak için bir sorgu yazmayı deneyin. Bu, tüm belgeleri şu şekilde döndürür;

{ 
    "id" : 1, 
    "school" : [ 
     { 
      "name" : "george", 
      "code" : "01" 
     }, 
     { 
      "name" : "michelangelo", 
      "code" : "01" 
     } 
    ], 
    "enrolledStudents" : [ 
     { 
      "userName" : "elisabeth", 
      "code" : 21 
     } 
    ] 
} 
{ 
    "id" : 2, 
    "school" : [ 
     { 
      "name" : "leonarda da vinci", 
      "code" : "01" 
     } 
    ], 
    "enrolledStudents" : [ 
     { 
      "userName" : "michelangelo", 
      "code" : 25 
     } 
    ] 
} 

cevap

2

Mongo 3,4

$match - Bu aşama tüm birleştirecek - En az bir gömülü belge hem sorgu koşulunu

$group eşleşen yoktur Bu, tüm school dizi tutacak sahne ve enrolledStudentsschool ve enrolledStudents dizisi, bir grupta her bir _id için 2d dizisine.

$project

- Bu aşama yeni etiketler values dizisi ile sorgu koşulunu ve $map dizi eşleştirme merge diziyi $filter edecektir.

$unwind - Bu aşama diziyi düzleştirecektir.

$addFields & $replaceRoot - Bu aşamalar id alan eklemek ve üstüne values dizi teşvik edecektir.= 3,2

db.collection.aggregate([ 
    {$match : {$or: [{"enrolledStudents.userName" : "michelangelo"} , {"school.name" : "michelangelo"}]}}, 
    {$group: {_id: "$id", merge : {$push:{$setUnion:["$school", "$enrolledStudents"]}}}}, 
    {$project: { 
     values: { 
       $map: 
       { 
        input: { 
          $filter: { 
           input: {"$arrayElemAt":["$merge",0]}, 
           as: "onef", 
           cond: { 
            $or: [{ 
             $eq: ["$$onef.userName", "michelangelo"] 
            }, { 
             $eq: ["$$onef.name", "michelangelo"] 
            }] 
           } 
          } 
         }, 
        as: "onem", 
        in: { 
         key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] }, 
         code : "$$onem.code"} 
       } 
      } 
     } 
    }, 
    {$unwind: "$values"}, 
    {$addFields:{"values.id":"$_id"}}, 
    {$replaceRoot: { newRoot:"$values"}} 
]) 

Numune Tepki

{ "_id" : 2, "key" : "michelangelo", "code" : 25 } 
{ "_id" : 1, "key" : "michelangelo", "code" : "01" } 

Mongo < tepkisini biçimlendirmek için $project yukarıdaki toplama son iki aşaması değiştirin.

{$project: {"_id": 0 , id:"$_id", key:"$values.key", code:"$values.code"}} 

Sen $redact yerine $group & match kullanımı ve tepkisini biçimlendirmek için $map ile $project ekleyebilir

{ "_id" : 2, "key" : "michelangelo", "code" : 25 } 
{ "_id" : 1, "key" : "michelangelo", "code" : "01" } 

örnek Tepki. Bir kerede bir belge seviyesinden geçmek ve eşleşen ölçütler için $$DESCEND ve $$PRUNE gerçekleştiren

$redact.

Dikkat edilmesi gereken tek şey, id için ilk belge düzeyinde $ifNull kullanımıdır; böylece daha fazla işlem için belge düzeyini $$DESCEND yapabilirsiniz.

db.collection.aggregate([ 
    { 
     $redact: { 
      $cond: [{ 
       $or: [{ 
        $eq: ["$userName", "michelangelo"] 
       }, { 
        $eq: ["$name", "michelangelo"] 
       }, { 
        $ifNull: ["$id", false] 
       }] 
      }, "$$DESCEND", "$$PRUNE"] 
     } 
    }, 
    { 
     $project: { 
      id:1, 
      values: { 
       $map: 
       { 
        input: {$setUnion:["$school", "$enrolledStudents"]}, 
        as: "onem", 
        in: { 
         key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] }, 
         code : "$$onem.code"} 
       } 
      } 
     } 
    }, 
    {$unwind: "$values"}, 
    {$project: {_id:0,id:"$id", key:"$values.key", code:"$values.code"}} 
]) 
İlgili konular