2016-03-02 220 views
0

我正在尝试查询来自错误日志集合的所有数据,并且在相同查询中为每个错误日志条目获取了相关irs_documents的计数。大数据集的Mongodb聚合查询计数记录

问题是,在irs_documents集合中执行$查找的记录太多。

是否有一个在一个MongoDB查询中执行此操作的高性能方法?

尝试失败

db.getCollection('errorlog').aggregate(
    [ 
    { 
     $lookup: { 
      from: "irs_documents", 
      localField: "document.ssn", 
      foreignField: "ssn", 
      as: "irs_documents" 
     } 
    }, 
    { 
     $group: { 
      _id: { document: "$document", error: "$error" }, 
      logged_documents: { $sum : 1 } 
     } 
    } 
    ] 
) 

错误

 
Total size of documents in $lookup exceeds maximum document size 

很明显,这个解决方案将无法工作。 MongoDB从字面上试图用$ lookup收集整个文档,我只是想要一个计数。

“错误日志” 采集样本数据:

 
/* 1 */ 
{ 
    "_id" : ObjectId("56d73955ce09a5a32399f022"), 
    "document" : { 
     "ssn" : 1 
    }, 
    "error" : "Error 1" 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("56d73967ce09a5a32399f023"), 
    "document" : { 
     "ssn" : 2 
    }, 
    "error" : "Error 1" 
} 

/* 3 */ 
{ 
    "_id" : ObjectId("56d73979ce09a5a32399f024"), 
    "document" : { 
     "ssn" : 3 
    }, 
    "error" : "Error 429" 
} 

/* 4 */ 
{ 
    "_id" : ObjectId("56d73985ce09a5a32399f025"), 
    "document" : { 
     "ssn" : 9 
    }, 
    "error" : "Error 1" 
} 

/* 5 */ 
{ 
    "_id" : ObjectId("56d73990ce09a5a32399f026"), 
    "document" : { 
     "ssn" : 1 
    }, 
    "error" : "Error 8" 
} 

“irs_documents” 采集样本数据

 
/* 1 */ 
{ 
    "_id" : ObjectId("56d73905ce09a5a32399f01e"), 
    "ssn" : 1, 
    "name" : "Sally" 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("56d7390fce09a5a32399f01f"), 
    "ssn" : 2, 
    "name" : "Bob" 
} 

/* 3 */ 
{ 
    "_id" : ObjectId("56d7391ace09a5a32399f020"), 
    "ssn" : 3, 
    "name" : "Kelly" 
} 

/* 4 */ 
{ 
    "_id" : ObjectId("56d7393ace09a5a32399f021"), 
    "ssn" : 9, 
    "name" : "Pippinpaddle-Oppsokopolis" 
} 

回答

1

该错误是自解释的。查找本质上是将两个文档合并到单个BSON文档中,因此MongoDB文档大小限制令人反感。

你需要问自己,是否绝对有必要在一个操作中执行两个操作?如果是的话,那么在以前版本的MongoDB中不得不执行$ lookup的操作。

表示执行两个查询并在您的客户端执行合并。

选项1:你可以聚集在irs_documents和出口计算的结果为另一个集合。因为每个文档中只有很少的对象,我认为你不会遇到问题。 但是,您可能会遇到内存问题并被迫使用磁盘进行聚合框架。尝试下面的解决方案,看看它是否工作。

db.irs_documents.aggregate([ 
{ 
    $group:{_id:"$ssn", count:{$sum:1}} 
}, 
{ 
    $out:"irs_documents_group" 
}]); 

db.errorlog.aggregate([ 
    { 
     $lookup: { 
      from: "irs_documents_group", 
      localField: "document.ssn", 
      foreignField: "ssn", 
      as: "irs_documents" 
     } 
    }, 
    { 
     $group: { 
      _id: { document: "$document", error: "$error" }, 
      logged_documents: { $sum : 1 } 
     } 
    } 
    ]) 

选项#2:如果上述方案不能正常工作,你总是可以使用地图降低,但它不会是一个完美的解决方案,但会奏效。

+0

谢谢你的回答。我目前使用两个查询。我主要发布了这个问题,以确定是否有一种方法将没有多次命中的计数附加到服务器上。 – ElephantHunter

+0

MongoDB使用术语“如果很多不是太多”执行$ lookup或在其他内嵌入相关文档,否则创建新的集合。在你的情况下,许多人真的很大,所以...... – Saleem