Обновление массива внутри массива дает ошибку 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"
}

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

Возможно, вы хотите сделать обновление, подобное этому примеру? Стандартной практикой является использование arrayFilters для выбора определенных элементов массива для обновления. Если вам нужно, я могу привести пример мангуста.

jQueeny 02.07.2024 13:38
Использование JavaScript и MongoDB
Использование JavaScript и MongoDB
Сегодня я собираюсь вкратце рассказать о прототипах в JavaScript, а также представить и объяснить вам работу с базой данных MongoDB.
0
1
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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});

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

если я хочу использовать первый метод, добавление условия типа {"batchInfo.batch_id": ObjectId("66834a6d4b221111587def7b"), "batchInfo.active": true} не поможет. Поскольку элемент batchInfo, имеющий batch_id, имеет active: false, он все равно обновляется. Как решить эту проблему?

user18181716 03.07.2024 06:13

Чтобы сопоставить более одного условия в элементе массива, вы можете использовать $elemMatch, чтобы гарантировать выполнение обоих условий. ВОТ пример.

jQueeny 03.07.2024 07:54

@jQuenny Большое спасибо. Вы такой полезный человек.

user18181716 04.07.2024 02:47

Другие вопросы по теме