sql >> Databasteknik >  >> NoSQL >> MongoDB

Gruppera efter dag med flera datumfält

Du kan också dela upp dokumenten vid källan genom att i huvudsak kombinera varje värde till en rad poster efter "typ" för "in" och "ut". Du kan göra detta helt enkelt med $map och $cond för att välja fälten och sedan $unwind arrayen och bestäm sedan vilket fält som ska "räknas" igen genom att inspektera med $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
        }
      }
    }
  }}
])

Det är ett säkert sätt att göra detta som inte riskerar att bryta BSON-gränsen, oavsett storleken på data du skickar till den.

Personligen skulle jag hellre köra som separata processer och "kombinera" de aggregerade resultaten separat, men det skulle bero på miljön du kör i, vilket inte nämns i frågan.

För ett exempel på "parallell" exekvering kan du strukturera i Meteor någonstans längs dessa linjer:

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

});

Som i huvudsak kommer att skickas till målsamlingen som nämndes i kommentarer som:

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


  1. MongoDB atomic findOrCreate:findOne, infoga om det inte finns, men uppdatera inte

  2. Sorterat set med fast storlek i Redis?

  3. Hur kan du specificera ordningen på egenskaper i ett javascript-objekt för ett MongoDB-index i node.js?

  4. Hur man kontrollerar att socket är levande (anslutet) i socket.io med flera noder och socket.io-redis