sql >> Databáze >  >> NoSQL >> MongoDB

Seskupit podle dne s více datovými poli

Dokumenty můžete také rozdělit u zdroje tak, že v podstatě zkombinujete každou hodnotu do pole položek podle „typu“ pro „in“ a „out“. Můžete to udělat jednoduše pomocí $map a $cond vyberte pole a poté $unwind pole a poté určete, které pole se má znovu "započítat" kontrolou pomocí $cond :

collection.aggregate([
  { "$project": {
    "dates": {
      "$filter": {
        "input": { 
          "$map": {
            "input": [ "in", "out" ],
            "as": "type",
            "in": {
              "type": "$$type",
              "date": {
                "$cond": {
                  "if": { "$eq": [ "$$type", "in" ] },
                  "then": "$inDate",
                  "else": "$outDate"
                }
              }
            }
          }
        },
        "as": "dates",
        "cond": { "$ne": [ "$$dates.date", null ] }
      }
    }
  }},
  { "$unwind": "$dates" },
  { "$group": {
    "_id": {
      "year": { "$year": "$dates.date" },
      "month": { "$month": "$dates.date" },
      "day": { "$dayOfMonth": "$dates.date" }
    },
    "countIn": {
      "$sum": {
        "$cond": {
          "if": { "$eq": [ "$dates.type", "in" ]  },
          "then": 1,
          "else": 0
        }
      }
    },
    "countOut": {
      "$sum": {
        "$cond": {
          "if": { "$eq": [ "$dates.type", "out" ]  },
          "then": 1,
          "else": 0
        }
      }
    }
  }}
])

Je to bezpečný způsob, jak toho dosáhnout, u kterého nehrozí prolomení limitu BSON, bez ohledu na to, jakou velikost dat na něj posíláte.

Osobně bych raději běžel jako samostatné procesy a „kombinoval“ agregované výsledky odděleně, ale to by záviselo na prostředí, ve kterém běžíte, což není v otázce zmíněno.

Pro příklad "paralelního" provádění můžete v Meteoru strukturovat někde v tomto smyslu:

import { Meteor } from 'meteor/meteor';
import { Source } from '../imports/source';
import { Target } from '../imports/target';

Meteor.startup(async () => {
  // code to run on server at startup

  await Source.remove({});
  await Target.remove({});

  console.log('Removed');

  Source.insert({
    "_id" : "XBpNKbdGSgGfnC2MJ",
    "po" : 72134185,
    "machine" : 40940,
    "location" : "02A01",
    "inDate" : new Date("2017-07-19T06:10:13.059Z"),
    "requestDate" : new Date("2017-07-19T06:17:04.901Z"),
    "outDate" : new Date("2017-07-19T06:30:34Z")
  });

  console.log('Inserted');

  await Promise.all(
    ["In","Out"].map( f => new Promise((resolve,reject) => {
      let cursor = Source.rawCollection().aggregate([
        { "$match": { [`${f.toLowerCase()}Date`]: { "$exists": true } } },
        { "$group": {
          "_id": {
            "year": { "$year": `$${f.toLowerCase()}Date` },
            "month": { "$month": `$${f.toLowerCase()}Date` },
            "day": { "$dayOfYear": `$${f.toLowerCase()}Date` }
          },
          [`count${f}`]: { "$sum": 1 }
        }}
      ]);

      cursor.on('data', async (data) => {
        cursor.pause();
        data.date = data._id;
        delete data._id;
        await Target.upsert(
          { date: data.date },
          { "$set": data }
        );
        cursor.resume();
      });

      cursor.on('end', () => resolve('done'));
      cursor.on('error', (err) => reject(err));
    }))
  );

  console.log('Mapped');

  let targets = await Target.find().fetch();
  console.log(targets);

});

Což je v podstatě výstup do cílové kolekce, jak bylo zmíněno v komentářích jako:

{
        "_id" : "XdPGMkY24AcvTnKq7",
        "date" : {
                "year" : 2017,
                "month" : 7,
                "day" : 200
        },
        "countIn" : 1,
        "countOut" : 1
}


  1. Závažná chyba:Třída 'MongoDB\Driver\Manager' nebyla nalezena

  2. MongoDB C# Driver projekce $elemMatch $

  3. Jak vytvořit model v DRY vzoru pomocí flow.js (pro asynchronní volání) v node.js?

  4. Počítejte na základě podmínky a vydělte počtem záznamů pro časový interval