2017-04-23 3 views
0

Ich bin neu bei Mongodb und NoSQL im Allgemeinen und ich versuche, mongodbs Aggregatfunktion zu verwenden, um Daten aus einer Sammlung zu aggregieren, um in eine andere eingefügt zu werden. Ein Beispiel der ursprünglichen Sammlung wäre dies:

Original-Sammlung { supplier: 'aldi', timestamp: '1492807458', user: '[email protected]', hasBeenAggregated:false, items:[{ name: 'butter', supplier: 'aldi', expiry: '1492807458', amount: 454, measureSymbol: 'g', cost: 2.19 },{ name: 'milk', supplier: 'aldi', expiry: '1492807458', amount: 2000, measureSymbol: 'ml', cost: 1.49 }] }

Ein Beispiel für die Ausgabe wäre ich versuche zu erreichen:

Neue Kollektion { user:'[email protected]', amount: 3.68, isIncome: false, title: 'food_shopping', timestamp: '1492807458' }

Die Aggregationsfunktion, die ich verwende, ist:

Aggregation var result = db.runCommand({ aggregate: 'food_transactions', pipeline: [ {$match: {hasBeenAggregated: false}}, {$unwind: '$items'}, {$group:{_id: '$_id',amount:{$sum: '$items.cost'}}}, {$project: { _id:0, user:1, amount:1, isIncome: {$literal: false}, title:{$literal: 'food_shopping'}, timestamp:1 }} ] }); printjson(result)

Diese Aggregationsfunktion kehrt nicht die user oder timestamp Felder aus. Stattdessen erhalte ich folgende Ausgabe:

Ausgabe { "amount" : 3.6799999999999997, "isIncome" : false, "title" : "food_shopping" }

Wenn ich die Ergebnisse nicht Gruppe tun und die Berechnungen in der $project Bühne, die Felder korrekt alle projiziert werden, aber offensichtlich gibt es ein neues Dokument, das für jedes Unterdokument im items-Array erstellt wurde und das den Zweck der Aggregation eher zunichte macht.

Was mache ich falsch?

Antwort

2

Aktualisieren Sie Ihre Pipeline $group, um alle Felder einzubeziehen, die Sie weiter unten in der Pipeline projizieren möchten.

Um Benutzerfeld gehören Sie $first

{$group:{_id: '$_id', user:{$first:'$user`}, amount:{$sum: '$items.cost'}}}, 

Zusätzlich verwenden können, wenn Sie 3.4-Version sind Sie Ihre Aggregation unten vereinfachen kann.

Verwenden Sie $reduce, um alle Kosten von item in einem einzigen Dokument zusammenzufassen. Für alle Dokumente können Sie $group nach $reduce hinzufügen.

db.collection.aggregate([ 
     {$match: {hasBeenAggregated: false}}, 
     {$project: { 
      _id:0, 
      user:1, 
      amount: { 
       $reduce: { 
       input: "$items", 
       initialValue: 0, 
       in: { $add : ["$$value", "$$this.cost"] } 
       } 
      }, 
      isIncome: {$literal: false}, 
      title:{$literal: 'food_shopping'}, 
      timestamp:1 
     }} 
    ]) 
Verwandte Themen