MongoDB-从带有时间戳的文档中获取最新的非空字段值

时间:2018-09-05 10:58:34

标签: mongodb

在我查询的MongoDB集合中,每个文档代表特定时间某个地块的一些数据。每次收到包裹更新时,某些字段可能会更新(非空值),而另一些字段则不更新(空值)。

为说明起见,请考虑以下示例。我们收到了一个包裹的3个数据集:

/* 1 */
{
    "parcelNum" : "CC123456789FR",
    "datetime" : ISODate("2018-09-05T10:48:38.584Z"),
    "field1" : "value1_1",
    "field2" : "value2_1"
}

/* 2 */
{
    "parcelNum" : "CC123456789FR",
    "datetime" : ISODate("2018-09-05T10:48:40.566Z"),
    "field1" : "value1_2",
    "field2" : null
}

/* 3 */
{
    "parcelNum" : "CC123456789FR",
    "datetime" : ISODate("2018-09-05T10:48:42.777Z"),
    "field1" : null,
    "field2" : "value2_2"
}

如何考虑到它们所属的文档的时间戳,为所有字段提取最新的非空值?

使用上一个示例,这就是我想要得到的:

{
    "parcelNum" : "CC123456789FR",
    "field1" : "value1_2",
    "field2" : "value2_2"
}

我尝试了这种查询,但是我找不到如何混合多个文档中的字段值:

db.testDB.aggregate([
    {$sort: { datetime: -1 }},
    {$group: { _id: "$parcelNum", 
        field1: {$first: "$field1" },
        field2: {$first: "$field2" }
    }}
])

给我:

{
    "_id" : "CC123456789FR",
    "field1" : null,
    "field2" : "value2_2"
}

这是错误的,因为它仅使用最新文档中的值,而不混合所有文档。

我尝试了Rishi在另一个主题中建议的另一种方法。他建议不要将修订版本的子文档推送到数组中,并在父文档中维护最新的修订版本,而不是为每个修订版本创建新文档。

类似这样的东西:

{
    parcelNum: CC123456789FR,
    lastUpdated: ISODate("2018-09-05T10:48:42.777Z")
    field1: "value1_2",
    field2: "value2_2",
    revisions: [
        {
            datetime: ISODate("2018-09-05T10:48:38.584Z"),
            field1: "value1_1",
            field2: "value2_1"
        },
        {
            datetime: ISODate("2018-09-05T10:48:40.566Z"),
            field1: "value1_2",
            field2: null
        },
        {
            datetime: ISODate("2018-09-05T10:48:42.777Z"),
            field1: null,
            field2: "value2_2"
        }
    ]
}

但是,维护最新修订版并不是那么容易,因为没有按时间顺序接收更新,那么我可以收到一个具有较旧“ datetime”字段值的“新”文档,然后除非出现以下情况,否则我不可以更新这些字段它们为空。然后,如果需要,我将必须记录所有字段的最后更新时间戳!

2 个答案:

答案 0 :(得分:1)

您可以尝试以下方法:

window

答案 1 :(得分:0)

您可以在$facet阶段尝试分别威胁field1和field2:

db['01'].aggregate(
    [
        // Stage 1
        {
            $sort: {
            "datetime":-1
            }
        },

        // Stage 2
        {
            $facet: {parcelNum:[{$group:{_id:"$parcelNum"}}],
                field1: [ {
                        $match: {
                        field1:{$ne:null}
                        }
                    },      
                    {
                        $limit: 1
                    },
                    {
                        $project: {
                         _id:0,
                         field1:1
                         }
                    }, ],

                field2: [ {
                        $match: {
                        field2:{$ne:null}
                        }
                    },      
                    {
                        $limit: 1
                    },
                    {
                        $project: {
                         _id:0,
                         field2:1
                         }
                    }, ],
            }
        },

        // Stage 3
        {
            $project: {
                parcelNum:"$parcelNum._id"  ,
                field1:"$field1.field1",
                field2:"$field2.field2",
            }
        },

        // Stage 4
        {
            $project: {
                parcelNum:{$arrayElemAt:["$parcelNum"  ,0]},
                field1:{$arrayElemAt:["$field1"  ,0]},
                field2:{$arrayElemAt:["$field2"  ,0]},
            }
        },
    ],
);

请注意,第3阶段和第4阶段只是“装饰性”,所需的结果出现在第2阶段的末尾。 希望对您有帮助