sql >> Database >  >> NoSQL >> MongoDB

Mongo / Mongoose - Samenvoegen op datum

Een goede benadering zou zijn om de geaggregeerde pijplijn op te splitsen in verschillende stappen met als doel de aggregaten met elke groep te berekenen, d.w.z. jaarlijkse, maandelijkse en wekelijkse aggregaten.

Ik heb een zwakke poging gedaan om de genoemde pijplijn te genereren, maar ik weet niet zeker of dat is wat u zoekt, maar ik zou u enkele aanwijzingen kunnen geven voor een oplossing, beter nog een optimale. Misschien kan iemand anders een beter antwoord geven.

Overweeg het volgende ongetest pijplijn:

db.statements.aggregate([
    {
        "$group": {
            "_id": {
                "name": "$name",
                "year": { "$year": "$date" },
                "month": { "$month": "$date" },
                "week": { "$week": "$date" }
            },
            "total": { "$sum": "$amount" }
        }
    },
    {
        "$group": {
            "_id": {
                "name": "$_id.name",
                "year": "$_id.year"
            },
            "YearlySpends": { "$push": "$total" },
            "totalYearlyAmount": { "$sum": "$total" },
            "data": { "$push": "$$ROOT" }
        }
    },
    { "$unwind": "$data" },
    {
        "$group": {
            "_id": {
                "name": "$_id.name",
                "month": "$data._id.month"
            },
            "YearlySpends": { "$first": "$YearlySpends" },
            "totalYearlyAmount": { "$first": "$totalYearlyAmount" },
            "MonthlySpends": { "$push": "$data.total" },
            "totalMonthlyAmount": { "$sum": "$data.total" },
            "data": { "$push": "$data" }
        }
    },
    { "$unwind": "$data" },
    {
        "$group": {
            "_id": {
                "name": "$_id.name",
                "week": "$data._id.week"
            },
            "YearlySpends": { "$first": "$YearlySpends" },
            "totalYearlyAmount": { "$first": "$totalYearlyAmount" },
            "MonthlySpends": { "$first": "$MonthlySpends" },
            "totalMonthlyAmount": { "$first": "$totalMonthlyAmount" },
            "WeeklySpends": { "$push": "$data.total" },
            "totalWeeklyAmount": { "$sum": "$data.total" },
            "data": { "$push": "$data" }
        }
    },
    { "$unwind": "$data" },
    {
        "$group": {
            "_id": "$data._id",
            "YearlySpends": { "$first": "$YearlySpends" },
            "totalYearlyAmount": { "$first": "$totalYearlyAmount" },
            "MonthlySpends": { "$first": "$MonthlySpends" },
            "totalMonthlyAmount": { "$first": "$totalMonthlyAmount" },
            "WeeklySpends": { "$first": "$WeeklySpends" },
            "totalWeeklyAmount": { "$first": "$totalWeeklyAmount" }
        }
    }
])

Voorbeelduitvoer

/* 1 */
{
    "_id" : {
        "name" : "Tesco",
        "year" : 2017,
        "month" : 3,
        "week" : 11
    },
    "YearlySpends" : [ 
        -3.3
    ],
    "totalYearlyAmount" : -3.3,
    "MonthlySpends" : [ 
        -3.3
    ],
    "totalMonthlyAmount" : -3.3,
    "WeeklySpends" : [ 
        -3.3
    ],
    "totalWeeklyAmount" : -3.3
}

/* 2 */
{
    "_id" : {
        "name" : "RINGGO",
        "year" : 2017,
        "month" : 4,
        "week" : 17
    },
    "YearlySpends" : [ 
        -3.3, 
        -26.3, 
        -33.3
    ],
    "totalYearlyAmount" : -62.9,
    "MonthlySpends" : [ 
        -33.3
    ],
    "totalMonthlyAmount" : -33.3,
    "WeeklySpends" : [ 
        -33.3
    ],
    "totalWeeklyAmount" : -33.3
}

/* 3 */
{
    "_id" : {
        "name" : "RINGGO",
        "year" : 2017,
        "month" : 3,
        "week" : 12
    },
    "YearlySpends" : [ 
        -3.3, 
        -26.3, 
        -33.3
    ],
    "totalYearlyAmount" : -62.9,
    "MonthlySpends" : [ 
        -3.3, 
        -26.3
    ],
    "totalMonthlyAmount" : -29.6,
    "WeeklySpends" : [ 
        -3.3
    ],
    "totalWeeklyAmount" : -3.3
}

/* 4 */
{
    "_id" : {
        "name" : "RINGGO",
        "year" : 2017,
        "month" : 3,
        "week" : 11
    },
    "YearlySpends" : [ 
        -3.3, 
        -26.3, 
        -33.3
    ],
    "totalYearlyAmount" : -62.9,
    "MonthlySpends" : [ 
        -3.3, 
        -26.3
    ],
    "totalMonthlyAmount" : -29.6,
    "WeeklySpends" : [ 
        -26.3
    ],
    "totalWeeklyAmount" : -26.3
}

/* 5 */
{
    "_id" : {
        "name" : "Sky",
        "year" : 2017,
        "month" : 3,
        "week" : 9
    },
    "YearlySpends" : [ 
        -63.3
    ],
    "totalYearlyAmount" : -63.3,
    "MonthlySpends" : [ 
        -63.3
    ],
    "totalMonthlyAmount" : -63.3,
    "WeeklySpends" : [ 
        -63.3
    ],
    "totalWeeklyAmount" : -63.3
}

/* 6 */
{
    "_id" : {
        "name" : "Amazon",
        "year" : 2017,
        "month" : 3,
        "week" : 12
    },
    "YearlySpends" : [ 
        -61.3
    ],
    "totalYearlyAmount" : -61.3,
    "MonthlySpends" : [ 
        -61.3
    ],
    "totalMonthlyAmount" : -61.3,
    "WeeklySpends" : [ 
        -61.3
    ],
    "totalWeeklyAmount" : -61.3
}

UPDATE

Als u filters wilt opnemen in de aggregatiebewerking, raad ik u aan de $match query als de eerste pijplijnfase. Als er echter een initiële $match stap, dan worden de voorgaande stappen enigszins gewijzigd omdat u gefilterde resultaten aggregeert, heel anders dan eerst alle documenten als geheel samen te voegen en vervolgens het filter op de resultaten toe te passen.

Als u de filter-first-then-aggregate route, overweeg dan een geaggregeerde bewerking uit te voeren die gebruikmaakt van $match als de eerste stap die de documenten op leverancier filtert, dan een voorafgaande $redact pijplijnstap om de documenten verder te filteren op het maandgedeelte van het datumveld en dan zou de rest de $group stadia:

Statements.aggregate([
    { "$match": { "name": req.params.vendor } },
    {
        "$redact": {
            "$cond": [
                { "$eq": [{ "$month": "$date" }, parseInt(req.params.month) ]},
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    },
    .....
    /*
        add the remaining pipeline steps after
    */
], function(err, data){
    if (err) throw err;
    console.log(data);
})

Als u de groep-eerst-dan-filter route, dan zou het filter na de laatste pijplijn zijn die het gegroepeerde resultaat geeft, maar toegepast op verschillende velden, omdat de documenten in dat deel van de stroom anders zouden zijn dan het oorspronkelijke schema.

Deze route is niet efficiënt omdat u de aggregatiebewerking begint met alle documenten in de verzameling en daarna filtert:

Statements.aggregate([
    .....
    /*
        place the initial pipeline steps from 
        the original query above here
    */
    .....
    { 
        "$match": { 
            "_id.name": req.params.vendor,
            "_id.month": parseInt(req.params.month)
        } 
    }
], function(err, data){
    if (err) throw err;
    console.log(data);
})

Voor meerdere datumfilterparameters, de $redacteren operator zou zijn

{
    "$redact": {
        "$cond": [
            {
                "$and": [
                     { "$eq": [{ "$year": "$date" },  parseInt(req.params.year)  ]},
                     { "$eq": [{ "$month": "$date" }, parseInt(req.params.month) ]},
                     { "$eq": [{ "$week": "$date" },  parseInt(req.params.week)  ]}
                ]
            },
            "$$KEEP",
            "$$PRUNE"
        ]
    }
}



  1. MongoDB-aggregatie over een bereik

  2. hoe de versie van de redis-instantie te controleren?

  3. Mongoose - sorteer datum alleen op datumgedeelte, negeer de tijd

  4. Hoe kan ik MongoWaitQueueFullException oplossen?