文件示例 https:/pastebin.comx2kVUnP3
了解数据
每一个字段的数组计数都与fetch_dates相同,所以如果我们想得到一个数据集,为 2019-06-07 05:34:29 它将返回所有的内部字段 $arrayElemAt = 1
对于最新的结果,对应的字段将是-1。
希望的结果
主要是重建所有文档,只保留每个字段的最新fetch_date和最后一个值。在这种情况下,只需保留图像的橙色线。
问题
基本上我不知道从哪里开始,如何开始,以及是否可以这样做。每个文档可以有不同的数组大小(fetch_dates),但结构是一样的。有225k个文档要处理,平均大小为2.5kb。如果有任何提示,将不胜感激。
我最初的想法是
我想通过一个PHP脚本得到所有的字段和它的最后一个元素,就像先迭代所有的文档,然后再迭代所有的字段和$project值。$arrayElemAt => [ $field3.field3_1, -1 ]
我想这是一个坏主意。
我使用的是PHP - Laravel,但我能够转换查询,让它在那里工作。
下面是一个纯粹从MongoDB的shell中得到的解决方案。
我的解决方案是依靠 汇聚管道 并使用 项目运作. 在你的问题中,你说:
每个文档可以有不同的数组大小(fetch_dates),但结构是一样的。
基于这一点,我认为没有必要对数据库中的所有文档进行迭代。相反,你可以只从数据库中提取一个文档,然后用它来得出一个投影,这个投影应该可以和数据库中的所有文档一起使用。这是我想出的代码。
function buildProjection(doc, prepend) {
var projection = {};
Object.keys(doc)
.forEach(key => {
var val = doc[key];
var path = prepend==null? key : prepend + '.' + key;
if (key == '_id') {
projection[key] = 1;
} else if ( Array.isArray(val) ) {
projection[key] = { '$slice' : [ '$'+path, -1 ] };
} else if ( typeof val === 'object' && val !== null ) {
projection[key] = buildProjection(val, path);
} else {
projection[key] = 1;
}
});
return projection;
}
/*
* Pull a document out of the database and build the projection based off of it.
* You may want to specify a particular document in the findone
* that you know to be structured correctly
*/
var sample = db.myCollection.findOne({});
var projection = buildProjection(sample, null);
db.myCollection.aggregate([
// apply the build projection
{ $project: projection },
// insert results into another collection
{ $out: 'rebuiltWithLatest' }
]);
我不确定你是否想把结果保存在另一个集合中。我用这个解决方案做了。它花了几秒钟,但我在运行这个30万个文档时没有任何问题,这些文档很像你的链接示例。
如果你只想查看文档,从聚合管道中删除$output操作。然后它将返回一个游标对象,你可以迭代查看其他结果。