sql >> Database >  >> NoSQL >> MongoDB

Groeperen op dag met meerdere datumvelden

U kunt de documenten ook bij de bron splitsen, door in wezen elke waarde te combineren in een reeks vermeldingen op "type" voor "in" en "uit". U kunt dit eenvoudig doen met $map en $cond om de velden te selecteren, dan $unwind de array en bepaal vervolgens welk veld opnieuw moet worden "geteld" door te inspecteren met $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
        }
      }
    }
  }}
])

Dat is een veilige manier om dit te doen zonder het risico te lopen de BSON-limiet te overschrijden, ongeacht de hoeveelheid gegevens die u ernaar verzendt.

Persoonlijk zou ik liever als afzonderlijke processen werken en de geaggregeerde resultaten afzonderlijk "combineren", maar dat zou afhangen van de omgeving waarin u draait, die niet in de vraag wordt genoemd.

Voor een voorbeeld van "parallelle" uitvoering, kunt u in Meteor ergens langs deze lijnen structureren:

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);

});

Wat in wezen naar de doelverzameling gaat, zoals vermeld in opmerkingen als:

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


  1. Hoe BSON Timestamp van Mongo changestream naar een datum te converteren?

  2. Is het mogelijk om de sleutel te definiëren bij het invoegen in mongodb

  3. MongoDB dropIndexes Commando

  4. MongoDB:vind waarde in array met meerdere criteria