2016-03-24 12 views
7

Chcę pokazywać produkty według identyfikatorów (56e641d4864e5b780bb992c6 i 56e65504a323ee0812e511f2) i wyświetlać cenę po odjęciu przez rabat, jeśli jest dostępna.

mogę liczyć na ostateczną cenę za pomocą agregatu, ale ten powrót wszystkich dokumentów w kolekcji, jak zrobić to wrócić tylko mecze identyfikatory

"_id" : ObjectId("56e641d4864e5b780bb992c6"), 
"title" : "Keyboard", 
"discount" : NumberInt(10), 
"price" : NumberInt(1000) 

"_id" : ObjectId("56e65504a323ee0812e511f2"), 
"title" : "Mouse", 
"discount" : NumberInt(0), 
"price" : NumberInt(1000) 

"_id" : ObjectId("56d90714a48d2eb40cc601a5"), 
"title" : "Speaker", 
"discount" : NumberInt(10), 
"price" : NumberInt(1000) 

to moje zapytanie

productModel.aggregate([ 
     { 
      $project: { 
       title : 1, 
       price: { 
        $cond: { 
         if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price" 
        } 

       } 
      } 
     } 
    ], function(err, docs){ 
     if (err){ 
      console.log(err) 
     }else{ 
      console.log(docs) 
     } 
    }) 

i jeśli dodać tę $in zapytanie, zwraca pustą tablicę

productModel.aggregate([ 
      { 
       $match: {_id: {$in: ids}} 
      }, 
      { 
       $project: { 
        title : 1, 
        price: { 
         $cond: { 
          if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price" 
        } 

       } 
      } 
     } 
    ], function(err, docs){ 
     if (err){ 
      console.log(err) 
     }else{ 
      console.log(docs) 
     } 
    }) 

Odpowiedz

11

Twoja zmienna ids będzie zbudowana z "łańcuchów", a nie z wartości ObjectId.

Mongoose "autocasts" wartości ciągu dla ObjectId na ich prawidłowy typ w regularnych zapytaniach, ale to does not happen in the aggregation pipeline, jak opisano w numerze # 1399.

Zamiast tego trzeba wykonać prawidłowy odlew ręcznie wpisać:

ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) }) 

Następnie można z nich korzystać w etapie rurociągu:

{ "$match": { "_id": { "$in": ids } } } 

Powodem jest fakt, rurociągi agregacji „typowo” zmienia strukturę dokumentu, a zatem mangusta nie zakłada domniemania, że ​​"schemat" odnosi się do dokumentu na dowolnym etapie procesu.

Można argumentować, że "pierwszy" etap rurociągu, gdy jest to etap $match, powinien to zrobić, ponieważ w rzeczywistości dokument nie został zmieniony. Ale teraz to nie tak się dzieje.

Wszelkie wartości, które mogą być "łańcuchami" lub co najmniej nieprawidłowym typem BSON, należy ręcznie obsadzić w celu dopasowania.

+0

To wszystko, teraz działa. ale zwykle wyrzucam id jako string w findOneAndUpdate lub innym zapytaniu i działa dobrze, czy problem występuje tylko w agregacie? –

+1

@MuhammadFasalirRahman Na to właśnie odpowiedziałem. '.find()' może używać 'schematu', który oczywiście ma domyślny typ' ObjectId' dla pola '_id'. Rurociągi agregujące nie ** używają schematu '' Schema', jak już to wyjaśniłem. –

+0

To nie działa w mangurze 5 –