1

My mongodb data is like this,i want to filter the memoryLine.

{
"_id" : ObjectId("5e36950f65fae21293937594"),
"userId" : "5e33ee0b4a3895a6d246f3ee",
"notes" : [ 
    {
        "noteId" : ObjectId("5e36953665fae212939375a0"),
        "time" : ISODate("2020-02-02T17:24:06.460Z"),
        "memoryLine" : [ 
            {
                "_id" : ObjectId("5e36953665fae212939375ab"),
                "memoryTime" : ISODate("2020-02-03T17:54:06.460Z")
            }, 
            {
                "_id" : ObjectId("5e36953665fae212939375aa"),
                "memoryTime" : ISODate("2020-02-03T05:24:06.460Z")
            }
        ]
    }
]}

i want to get the item which memoryTime is great than now as expected like this,

"userId" : "5e33ee0b4a3895a6d246f3ee",
"notes" : [ 
    {
    "noteId" : ObjectId("5e36953665fae212939375a0"),
    "time" : ISODate("2020-02-02T17:24:06.460Z"),
    "memoryLine" : [ 
        {
            "_id" : ObjectId("5e36953665fae212939375ab"),
            "memoryTime" : ISODate("2020-02-03T17:54:06.460Z")
        }, 
        {
            "_id" : ObjectId("5e36953665fae212939375aa"),
            "memoryTime" : ISODate("2020-02-03T05:24:06.460Z")
        }
    ]
}]

so is use code as below.i use a $filter in memoryLine to filter to get the right item.

aggregate([{
    $match: {
        "$and": [
            { userId:  "5e33ee0b4a3895a6d246f3ee"},
        ]
    }
}, {
    $project: {
        userId: 1,
        notes: {
            noteId: 1,
            time: 1,
            memoryLine: {
                $filter: {
                    input: "$memoryLine",
                    as: "mLine",
                    cond: { $gt: ["$$mLine.memoryTime", new Date(new Date().getTime() + 8 * 1000 * 3600)] }
                }
            }
        }
    }
}]).then(doc => {
    res.json({
        code: 200,
        message: 'success',
        result: doc
    })
});

but i got this,memoryLine is null,why?I try to change $gt to $lt, but also got null.

"userId" : "5e33ee0b4a3895a6d246f3ee",
"notes" : [ 
    {
    "noteId" : ObjectId("5e36953665fae212939375a0"),
    "time" : ISODate("2020-02-02T17:24:06.460Z"),
    "memoryLine" : null  <<<-------------  here is not right
}]

1 Answer 1

1

You can use $addFields to replace existing field, $map for outer collection and $filter for inner:

db.collection.aggregate([
    {
        $addFields: {
            notes: {
                $map: {
                    input: "$notes",
                    in: {
                        $mergeObjects: [
                            "$$this",
                            { 
                                memoryLine: {
                                    $filter: {
                                        input: "$$this.memoryLine",
                                        as: "ml",
                                        cond: {
                                            $gt: [ "$$ml.memoryTime", new Date() ]
                                        }
                                    }
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
])

$mergeObjects is used to avoid repeating fields from source memoryLine object.

Mongo Playground

Sign up to request clarification or add additional context in comments.

2 Comments

thank you very much.Can you tell me why my code with filter is wrong.I study from here docs.mongodb.com/manual/reference/operator/aggregation/filter
@JackieWillen single $filter is totally fine when you have single array. In your case your array is nested inside of another array so you need to deal with the outer one first - that's why you need to run $map

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.