Срез Mongoose не ограничивает размер массива

Я работаю над приложением, и у меня возникла проблема с ограничением размера массива Mongoose при обновлении. Я не слишком знаком с MongoDB или Mongoose, но надеюсь, что этот проект расширит мои знания. Я попробовал несколько других решений, которые я запрашивал в SOF, но ни одно из них не помогло мне. Вот моя разбивка проблемы ...

Библиотека: Mongoose 5.7.7

Резюме. В документе журналов я хочу хранить только 10 последних журналов, при этом более старые журналы выталкиваются из массива.

Проблема: с текущим запросом, который у меня есть, кажется, что срез не ограничивает количество документов. Массив просто продолжает расти.

ActivityLog.updateOne(
  { guild },
  {
    $push: {
      logs: {
        $each: [{ ...log }]
      },
      $slice: -10
    }
  },
  { upsert: true }
);

person Rykuno    schedule 30.10.2019    source источник


Ответы (1)


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

const { Schema } = mongoose = require('mongoose');

const uri = 'mongodb://localhost:27017/test';
const options = { useNewUrlParser: true, useUnifiedTopology: true };

mongoose.set("debug", true);
mongoose.set("useFindAndModify", false);
mongoose.set("useCreateIndex", true);

const demoSchema = new Schema({
  _id: Number,
  fifo: [Number]
},{ _id: false });

const Demo = mongoose.model('Demo', demoSchema, 'demo');

const log = data => console.log(JSON.stringify(data, undefined, 2));

(async function() {

  try {

    const conn = await mongoose.connect(uri, options);

    await Promise.all(
      Object.values(conn.models).map(m => m.deleteMany())
    );

    let counter = 0;

    await new Promise((resolve, reject) =>
      setInterval(async () => {
        try {
          let result = await Demo.findByIdAndUpdate(
            1,
            { "$push": { "fifo": { "$each": [counter], "$slice": -3 } } },
            { upsert: true, new: true }
          );

          log(result);
        } catch(e) {
          reject(e)
        }
        counter++;
      }, 2000)
    );


  } catch (e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }

})()

На нескольких итерациях (здесь для краткости используется -3) вы увидите:

Mongoose: demo.deleteMany({}, {})
Mongoose: demo.findOneAndUpdate({ _id: 1 }, { '$setOnInsert': { __v: 0 }, '$push': { fifo: { '$each': [ 0 ], '$slice': -3 } }}, { upsert: true, remove: false, projection: {}, returnOriginal: false })
{
  "fifo": [
    0
  ],
  "_id": 1,
  "__v": 0
}
Mongoose: demo.findOneAndUpdate({ _id: 1 }, { '$setOnInsert': { __v: 0 }, '$push': { fifo: { '$each': [ 1 ], '$slice': -3 } }}, { upsert: true, remove: false, projection: {}, returnOriginal: false })
{
  "fifo": [
    0,
    1
  ],
  "_id": 1,
  "__v": 0
}
Mongoose: demo.findOneAndUpdate({ _id: 1 }, { '$setOnInsert': { __v: 0 }, '$push': { fifo: { '$each': [ 2 ], '$slice': -3 } }}, { upsert: true, remove: false, projection: {}, returnOriginal: false })
{
  "fifo": [
    0,
    1,
    2
  ],
  "_id": 1,
  "__v": 0
}
Mongoose: demo.findOneAndUpdate({ _id: 1 }, { '$setOnInsert': { __v: 0 }, '$push': { fifo: { '$each': [ 3 ], '$slice': -3 } }}, { upsert: true, remove: false, projection: {}, returnOriginal: false })
{
  "fifo": [
    1,
    2,
    3
  ],
  "_id": 1,
  "__v": 0
}
Mongoose: demo.findOneAndUpdate({ _id: 1 }, { '$setOnInsert': { __v: 0 }, '$push': { fifo: { '$each': [ 4 ], '$slice': -3 } }}, { upsert: true, remove: false, projection: {}, returnOriginal: false })
{
  "fifo": [
    2,
    3,
    4
  ],
  "_id": 1,
  "__v": 0
}
Mongoose: demo.findOneAndUpdate({ _id: 1 }, { '$setOnInsert': { __v: 0 }, '$push': { fifo: { '$each': [ 5 ], '$slice': -3 } }}, { upsert: true, remove: false, projection: {}, returnOriginal: false })
{
  "fifo": [
    3,
    4,
    5
  ],
  "_id": 1,
  "__v": 0
}
Mongoose: demo.findOneAndUpdate({ _id: 1 }, { '$setOnInsert': { __v: 0 }, '$push': { fifo: { '$each': [ 6 ], '$slice': -3 } }}, { upsert: true, remove: false, projection: {}, returnOriginal: false })
{
  "fifo": [
    4,
    5,
    6
  ],
  "_id": 1,
  "__v": 0
}

Таким образом, это действительно сохраняет массив указанной длины $slice и с конца массива, поскольку из-за отрицательного значения, как увеличение массива до установленного размера, так и удаление всех, кроме последних добавленных элементов.

person Neil Lunn    schedule 30.10.2019
comment
Я развернул небольшой проект, чтобы убедиться, что он работает. Вы упомянули, что это может быть способ, которым я это реализовал, есть ли у вас какие-либо идеи или подробности по этому поводу? - person Rykuno; 30.10.2019
comment
@Rykuno Я полагаю, что понимание будет примером рабочего кода перед вами, который вы прокомментировали. В этом весь смысл. Как видно из ответа, работает так, как задумано. - person Neil Lunn; 31.10.2019
comment
Я понимаю, что ваш пример работает. Но для нашей реализации мне было интересно, в чем проблема и почему она не режет :). На самом деле это может быть больше проблемой в вашей реализации. ‹- Я ищу разъяснения по этому поводу, я полагаю, извините за недопонимание. Я буду работать над этим сегодня, поэтому я обновлю, если найду решение - person Rykuno; 01.11.2019
comment
Пошел вперед и опубликовал как принятый ответ, так как я использовал его для решения своей проблемы. Моя проблема заключалась в простом кронштейне. Срез $ должен находиться в том же объекте, что и оператор $ each. Цифры это было что-то такое простое. - person Rykuno; 02.11.2019