2016-09-16 52 views
0

我正在嘗試計算集合的子數組中的字段,並且我想每個月都這樣做。我曾在Mongo 2.6中工作,但最近升級到3.0.12在查詢中導致了一些錯誤的結果。它幾乎看起來像是沒有得到重置的幾個查詢。如何在MongoDB集合中分別累計幾個月的數據

因此,目前我正在做12個查詢異步並等待他們全部完成。這又是在2.6中工作。我的表結構是這樣的:

{ 
"_id" : ObjectId("<id>"), 
"userId" : ObjectId("<id>"), 
"accountId" : "1234567890", 
"transactionId" : "22222222333", 
"date" : ISODate("2016-09-08T04:00:00.000Z"), 
"description" : "SUPERCOOL STORE", 
"amount" : -123.45, 
"allocations" : [ 
    { 
     "jarId" : ObjectId("566faf1937af9ae11ef84bc4"), 
     "amount" : -100 
    }, 
    { 
     "jarId" : ObjectId("566faf1937af9ae11ef84bc1"), 
     "amount" : -23.45 
    } 
], 
"reconciled" : true, 
"tally" : true, 
"split" : true 
} 

這是我的代碼:

var getTransactionAggregate = function (userId, month) { 
    var deferred = q.defer(); 
    var nextMonth = moment(month).add(1, 'M'); 

    Transactions.aggregate([ 
    {$match: { 
     userId: userId, 
     tally: true, 
     date: { 
     $gte: month.toDate(), 
     $lt: nextMonth.toDate() 
     } 
    }}, 
    {$project: { _id: 0, allocations: 1 } }, 
    {$unwind: '$allocations'}, 
    {$group: {_id: '$allocations.jarId', total: {$sum: '$allocations.amount'}}} 
    ]).then(function(data) { 
    deferred.resolve(data); 
    }) 
    .catch(function (err) { 
    logger.error(err); 
    deferred.reject(err); 
    }); 

    return deferred.promise; 
}; 

summaryReport = function (req, res) { 
    Jars.aggregate([ 
    { $match: {userId: new ObjectID(req.user._id)} }, 
    { $sort: {name: 1} } 
    ]) 
    .then(function (jars) { 
    var month = moment(moment().format('YYYY-MM') + '-01T00:00:00.000'); 
    var i, j; 
    var promises = []; 

    for (i = 0; i < 12; i++) { 
     promises.push(getTransactionAggregate(new ObjectID(req.user._id), month)); 
     month.add(-1, 'M'); 
    } 

    q.allSettled(promises).then(function (data) { 
     for (i = 0; i < data.length; i++) { 
     // data[i].value here is returned incorrectly from the queries 

     ........ 
    }); 
    }); 
}; 

所以基本上所發生的事情是第一個月包括正確的數據,但似乎總和繼續包括數據從前幾個月。如果我分解查詢,日期範圍內將返回正確的事務,並且展開也正常工作。正當這個羣體的步驟似乎是罪魁禍首。在我將Mongo升級到3.0.12之前,同樣的邏輯工作正常。

有沒有更好的方法來執行此查詢在一個鏡頭中或正在做十二個查詢的最佳方式?

回答

0

它結束了正相關的比賽雖然沒有在上面的回答中提到的$和情況,因爲。它必須與日期匹配,我猜object.toDate()不會返回與使用新Date()時相同的日期對象,儘管我認爲它們是相同的。

反正工作邏輯是這樣的:

Transactions.aggregate([ 
    {$match: { 
    userId: userId, 
    tally: true, 
    $and: [ 
     { date: { $gt : new Date(month.toISOString()) } }, 
     { date: { $lt: new Date(nextMonth.toISOString()) } } 
    ] 
    }}, 
    {$unwind: '$allocations'}, 
    {$group: {_id: '$allocations.jarId', total: {$sum: '$allocations.amount'}}} 
]) 

感謝Date query with ISODate in mongodb doesn't seem to work和@Leif指着我在正確的方向。

1

這在$match階段似乎是一個問題。您date字段有兩種表現形式,而這種情況下,你需要使用$and運營商,如docs規定:

MongoDB的指定用逗號分隔的 表達式列表時提供了一種隱含AND運算。當在多個表達式中指定相同的字段或運算符必須是 時,對$和 運算符使用顯式AND是必要的。

所以就變成:

{$match: { 
    userId: userId, 
    tally: true, 
    $and: [ 
     { date: { $gte : month.toDate() } }, 
     { date: { $lt: nextMonth.toDate() } } 
    ] 
}} 
+0

感謝您的快速響應!你是對的,它必須與比賽有關,我只是把邏輯迴歸到第一原則,每月只有1件和總共3個月,第一個月的查詢返回所有三個項目,第二個月只返回2,上個月返回正確匹配的一個項目。 但是,按照您的建議改變匹配邏輯似乎沒有幫助。我也沒有把我所有的標準都放在$和$。 – Eric