Обновление массива внутри массива дает ошибку Location40324 в mongodb

Я создаю систему управления студентами. Я использую nodejs, expressjs, ejs и mongoose. Вот код модели Student:

const mongoose = require('mongoose')
const studentSchema = mongoose.Schema({
    name: {type: String, required: true},
    batchInfo: [{
        batch_id: {type: mongoose.Schema.Types.ObjectId, ref: "Batch", required: true},
        studentID: {type: String, required: true, unique: true},
        payments: [{type: Number, required: true}],
        active: {type: Boolean, required: true}
    }],
})
const Student = mongoose.model('Student', studentSchema, 'students')
module.exports = Student

В массиве batchInfo должна быть информация о другой партии.

У меня есть такой студенческий документ:

{
    "_id": "6683591adb3c21133fd99e12",
    "name": "John",
    "batchInfo": [
    {
        "batch_id": "66834a6d4b221111587def7b",
        "studentID": "252105",
        "payments": [2000, 1000]
        "active": false
    },
    {
        "batch_id": "668353316c57406f16e14449",
        "studentID": "252301",
        "payments": [1000]
        "active": true,
    }
  ]
}

Я фильтрую этот документ по массиву batchInfo, имеющему "active": true. Я получил этот документ:

{
    "_id": "6683591adb3c21133fd99e12",
    "name": "John",
    "batchInfo": [
    {
        "batch_id": "668353316c57406f16e14449",
        "studentID": "252301",
        "active": true,
        "payments": [1000]
    }
  ]
}

Чтобы получить этот документ, я применил этот экспресс-код:

const mongoose = require('mongoose')
const Student = require("./models/Student")
app.post('/update/:id', async function (req, res) {
    try {
        const student = await Student.aggregate([
            {"$match": {_id: new mongoose.Types.ObjectId(req.params.id)}},
            {"$project": {batchInfo: {"$filter": {input: "$batchInfo", as: "item", cond: {"$eq": ["$$item.active", true]}}}, name: 1}}
        ])
        res.send(student[0])
    } catch (error) {
        res.send(error)
    }
})

Теперь я хочу вставить элемент в массив payments. Итак, я попробовал этот код:

const mongoose = require('mongoose')
const Student = require("./models/Student")
app.post('/update/:id', async function (req, res) {
    try {
        const student = await Student.aggregate([
            {"$match": {_id: new mongoose.Types.ObjectId(req.params.id)}},
            {"$project": {batchInfo: {"$filter": {input: "$batchInfo", as: "item", cond: {"$eq": ["$$item.active", true]}}}, name: 1}},
            {"$push": {"batchInfo.payments": 3000}}
        ])
        res.send(student[0])
    } catch (error) {
        res.send(error)
    }
})

Попробовав этот код, я получил такую ​​ошибку:

{
  "ok": 0,
  "code": 40324,
  "codeName": "Location40324"
}

Как решить эту проблему?

🤔 А знаете ли вы, что...
MongoDB поддерживает шардирование данных для распределения нагрузки и хранения больших наборов данных...


61
1

Ответ:

Решено

Существует несколько различных подходов к обновлению элементов массива путем добавления нового значения в массив.

Если вы знаете, что нашли только один элемент массива, вы можете просто использовать позиционный оператор $push для обновления первого соответствующего элемента массива в методе $ следующим образом:

const student = await Student.findOneAndUpdate({
  _id: new mongoose.Types.ObjectId(req.params.id),
  "batchInfo.active": true //< must match array element too
},
{
  $push: {
    "batchInfo.$.payments": 3000
  }
}, {new: true});

Рабочий пример смотрите ЗДЕСЬ.

Альтернативно вы можете обновить несколько элементов массива, используя опцию findOneAndUpdate(), например:

const student = await Student.findOneAndUpdate({
  _id: new mongoose.Types.ObjectId(req.params.id)
},
{
  $push: {
    "batchInfo.$[element].payments": 3000
  }
},
{
  arrayFilters: [
    {
      "element.active": true
    }
  ]
});

Рабочий пример смотрите ЗДЕСЬ.

Чтобы сопоставить один элемент массива на основе нескольких условий, вы можете использовать arrayFilters следующим образом:

const student = await Student.findOneAndUpdate({
  _id: new mongoose.Types.ObjectId(req.params.id),
  batchInfo: {
    $elemMatch: {
      active: true,
      batch_id: new mongoose.Types.ObjectId("668353316c57406f16e14420")
    }
  {
},
{
  $push: {
    "batchInfo.$.payments": 3000
  }
}, {new: true});

Рабочий пример смотрите ЗДЕСЬ.