2017-02-08 47 views
12

Jestem nowicjuszem. Ale staram się nauczyć najbardziej logicznych sposobów pisania zapytań.Wartość wyszukiwania w 2 różnych polach mongodb + node.js

Załóżmy, że mam kolekcję, która jest jak;

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

Chcę wymienić wystąpienie o key z odpowiadającymi im code wartości.

Jako przykład key: michelangelo

aby znaleźć wystąpienie klucza, napisałem dwa tarasowy aggregation zapytań jak;

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

i

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

wynikiem tych 2 zapytaniami powrócić czego chcę jak;

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

Jeden z nich, aby szukać w enrolledStudents, drugi szuka w school dziedzinie.

Czy te 2 zapytania można zredukować do bardziej logicznego zapytania? A może to jedyny sposób na zrobienie tego?

ps: Wiem, że struktura bazy danych nie jest logiczna, ale próbowałem symulować.

edycja Próbuję napisać zapytanie z find.

db.test.find({$or: [{"enrolledStudents.userName" : "michelangelo"} , {"school.name" : "michelangelo"}]}).pretty() 

ale to zwraca całą dokumentację jako;

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

Odpowiedz

2

Mongo 3,4

$match - Ten etap będzie utrzymywać cały wachlarz school i enrolledStudents gdzie jest conajmniej jeden dokument osadzony dopasowanie zarówno warunek zapytania

$group - Ten etap będzie połączyć wszystkie tablica school i enrolledStudents na tablicę 2d dla każdego _id w grupie.

$project - Ten etap będzie $filter tablicę merge dopasowywania stan kwerendy i $map tablicy do nowych etykiet values tablicy.

$unwind - Ten etap spowoduje spłaszczenie tablicy.

$addFields & $replaceRoot - to etapy doda pole id i promowania tablicę do góry values.

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

Response Próbka

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

Mongo < = 3,2

Wymień dwa ostatnie etapy powyżej agregacji z $project formatować odpowiedzi.

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

Response Próbka

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

Można użyć $redact zamiast $group & match i dodać $project z $map formatować odpowiedzi.

$redact, aby przejść przez poziom dokumentu na raz i wykonać $$DESCEND i $$PRUNE w sprawie pasujących kryteriów.

Należy zwrócić uwagę tylko na użycie $ifNull na pierwszym poziomie dokumentu dla id, dzięki czemu można $$DESCEND osadzić poziom dokumentu do dalszego przetwarzania.

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