【问题标题】:Adding a new field to the N most reset docs by day in MongoDB 4.2在 MongoDB 4.2 中每天向 N 个最重置的文档添加一个新字段
【发布时间】:2020-05-10 19:25:10
【问题描述】:

我有一组带有方案的文档:

{ _id: ObjectId, userId: ObjectId, marker: string, datetime: Date, etc... }

这是与用户 (userId) 绑定的标记 (marker) 的集合。绑定日期存储在datetime字段中。

每天用户可以收到任意数量的标记。

当我从这个集合中获取数据时,我需要添加一个名为allowed 类型为boolean 的额外字段,并且该字段必须是true,仅当此记录位于N 个最近发送的记录中时用户的日历日。

例如,如果初始集合看起来像这样并且 N == 2

{_id: ..., userId: "a", marker: "m1", datetime: "2020-01-01.10:00"}
{_id: ..., userId: "a", marker: "m2", datetime: "2020-01-02.10:00"}
{_id: ..., userId: "a", marker: "m3", datetime: "2020-01-02.11:00"}
{_id: ..., userId: "a", marker: "m4", datetime: "2020-01-02.12:00"}
{_id: ..., userId: "a", marker: "m5", datetime: "2020-01-02.13:00"}
{_id: ..., userId: "b", marker: "m1", datetime: "2020-01-01.10:00"}
{_id: ..., userId: "b", marker: "m2", datetime: "2020-01-01.11:00"}
{_id: ..., userId: "b", marker: "m3", datetime: "2020-01-01.13:00"}
{_id: ..., userId: "b", marker: "m4", datetime: "2020-01-02.11:00"}
{_id: ..., userId: "b", marker: "m5", datetime: "2020-01-02.12:00"}
{_id: ..., userId: "b", marker: "m6", datetime: "2020-01-03.10:00"}

那么最终的结果应该是这样的:

{_id: ..., userId: "a", marker: "m1", datetime: "2020-01-01.10:00", allowed: true}
{_id: ..., userId: "a", marker: "m2", datetime: "2020-01-02.10:00", allowed: true}
{_id: ..., userId: "a", marker: "m3", datetime: "2020-01-02.11:00", allowed: true}
{_id: ..., userId: "a", marker: "m4", datetime: "2020-01-02.12:00", allowed: false}
{_id: ..., userId: "a", marker: "m5", datetime: "2020-01-02.13:00", allowed: false}
{_id: ..., userId: "b", marker: "m1", datetime: "2020-01-01.10:00", allowed: true}
{_id: ..., userId: "b", marker: "m2", datetime: "2020-01-01.11:00", allowed: true}
{_id: ..., userId: "b", marker: "m3", datetime: "2020-01-01.13:00", allowed: false}
{_id: ..., userId: "b", marker: "m4", datetime: "2020-01-02.11:00", allowed: true}
{_id: ..., userId: "b", marker: "m5", datetime: "2020-01-02.12:00", allowed: true}
{_id: ..., userId: "b", marker: "m6", datetime: "2020-01-03.10:00", allowed: true}

我正在使用 MongoDB 4.2。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    请尝试以下查询:

    查询 1:

     db.markers.aggregate([
        /** group docs based on userId & date(2020-01-01), push all matched docs to data */
        { $group: { _id: { userId: '$userId', datetime: { $arrayElemAt: [{ $split: ["$datetime", "."] }, 0] } }, data: { $push: '$$ROOT' } } },
        /** Re-forming data field with added new field allowed for only docs where criteria is met */
        {
            $addFields: {
                data: {
                    $map:
                    {
                        input: "$data",
                        as: "each",
                        /** conditional check to add new field on only docs which are 0 & 1 position of array */
                        in: { $cond: [{ $lte: [{ $indexOfArray: ["$data", '$$each'] }, 1] }, { $mergeObjects: ['$$each', { allowed: true }] }, { $mergeObjects: ['$$each', { allowed: false }] }] }
                    }
                }
            }
        },
        /** unwind data */
        { $unwind: '$data' },
        /** making data object as root level doc */
        { $replaceRoot: { newRoot: "$data" } }])
    

    查询 2:

    db.markers.aggregate([
        { $group: { _id: { userId: '$userId', datetime: { $arrayElemAt: [{ $split: ["$datetime", "."] }, 0] } }, data: { $push: '$$ROOT' } } }, {
            $addFields: {
                data: {
                    $map:
                    {
                        input: "$data",
                        as: "each",
                        in: {
                            $cond: [{
                                $or: [{ $eq: [{ $arrayElemAt: ["$data", -1] }, '$$each'] }, { $eq: [{ $arrayElemAt: ["$data", -2] }, '$$each'] }]
                            },
                            { $mergeObjects: ['$$each', { allowed: true }] },
                            { $mergeObjects: ['$$each', { allowed: false }] }]
                        }
                    }
                }
            }
        }, { $unwind: '$data' }, { $replaceRoot: { newRoot: "$data" } }])
    

    Query1 将起作用并为您提供结果,但假设所给出的数据是样本数据,并且当您查看集合时实时,userId: "a", marker: "m5" 将是第一个文档,就好像这个集合有连续数据写入然后最新文档将具有最新的data time,因此 Query1 的索引 0 或 1 将不起作用,但这里 Query2 会起作用。如果标记集合具有与问题中给出的完全相同的有序数据,则可以使用 Query1

    注意:Query2 - 我们可以使用与 Query1 相同的逻辑(即检查索引(0,1))而不是对象比较,但这只有在我们将$sortdateTime 字段作为第一阶段时才适用,而且我没有走那条路是因为对字段上的整个集合的数据进行排序不会比这更有效。

    【讨论】:

      猜你喜欢
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      相关资源
      最近更新 更多