Сопоставить, обновить и вернуть последний поддокумент в массиве - PullRequest
1 голос
/ 17 июня 2020

Я хочу сопоставить поддокументы в массиве и обновить последний элемент. Этот запрос обновляет только документ с changeId 0, хотя я получил документ с идентификатором 2 в массиве ...

const oldDocument = await schemas.Collection.findOneAndUpdate(
                        {
                            "_id": new ObjectId(_id),
                            "manualChanges.id": update.id,
                            "manualChanges.discarded": false
                        },
                        {
                            $set: {
                                "manualChanges.$.discarded": true
                            }
                        },
                        {
                            sort: {'manualChanges.changeId': -1},
                            projection: {"manualChanges.$": 1}
                        }
                    );
                    console.log(oldDocument);

После этого я хочу вернуть единственный обновленный документ, который, к сожалению, также работает только без сорта ..

1 Ответ

1 голос
/ 17 июня 2020

Из $ (позиционный оператор) docs:

позиционный оператор $ действует как заполнитель для первого элемента, который соответствует документу запроса, и

Позиционный оператор всегда соответствует первому документу в массиве, поэтому я предполагаю, что вы пытались выполнить сортировку по убыванию. Однако, хотя вы могли подумать, что этот подход может работать, он не будет работать, поскольку sort является оператором курсора, что означает, что он влияет только на сопоставление документа. Фактически невозможно отсортировать вложенный массив в Mon go до грядущей версии 4.4, где планируется ввести пользовательские функции.

Итак, что вы можете сделать? Если вы используете Mon go версии 4.2+, они представили конвейерные обновления , что дает нам больше возможностей, позволяя нам использовать выражения агрегации в обновлении, вот пример того, что с ним можно сделать:

db.test.updateOne(
    {
        "_id": new ObjectId(_id),
    },
    [
        {
            $set: {
                filtered: {
                    $filter: {
                        input: "$manualChanges",
                        as: "change",
                        cond: {$ne: ["$$change.discarded", true]}
                    }
                }
            }
        },
        {
            $set: {
                last_id: {
                    $max: "$filtered.id",
                }
            }
        },
        {
            $set: {
                manualChanges: {
                    $map: {
                        input: "$manualChanges",
                        as: "change",
                        in: {
                            $mergeObjects: [
                                "$$change",
                                {
                                    discarded: {$cond: [{$eq: ["$$change.id", "$last_id"]}, true, "$$change.discarded"]}
                                }
                            ]
                        }
                    }
                }
            }
        },
        {
            $unset: ["last_id", "filtered"]
        }
    ])

Если вы используете более низкую версию Mon go, вам придется разделить это на 2 запроса, сначала найдите дополнительный документ id и только потом вы сможете его обновить.

...