Mongoose: найдите документ и обрежьте элементы массива, которые не соответствуют условию

у меня есть такие документы:

{
  "_id": {
    "$oid": "630656bfc64b4c94c5c5a614"
  },
  "collectionId": {
    "$oid": "630654a37a2a8ea9e11b6803"
  },
  "__v": 0,
  "createdAt": {
    "$date": {
      "$numberLong": "1661359804637"
    }
  },
  "stats": [
    {
      "floor": 0.005,
      "volume": 3.288569999999999,
      "listedCount": 57,
      "timestamp": {
        "$date": {
          "$numberLong": "1661359800000"
        }
      },
      "_id": {
        "$oid": "630656bc7a2a8ea9e11bc74b"
      }
    },
    {
      "floor": 0.0001,
      "volume": 3.081616000000002,
      "listedCount": 88,
      "timestamp": {
        "$date": {
          "$numberLong": "1661360400000"
        }
      },
      "_id": {
        "$oid": "6306591e7a2a8ea9e11c2479"
      }
    },
  ],
  "updatedAt": {
    "$date": {
      "$numberLong": "1661530019840"
    }
  }
}

Где статистика - это массив объектов, и иногда в этом массиве может быть более 1000 элементов. Как видите, объекты внутри статистики имеют отметку времени. Теперь я хочу возвращать только документы, соответствующие определенному условию, например:

{ 'stats.timestamp': { '$gt': '2022-08-22' } }

На данный момент все в порядке, это вернет все документы, которые есть stats.timestamp > 2022-08-22

Но, как я уже сказал, мой массив статистики может состоять из 1000+ элементов, а в будущем он вырастет более чем на 10000+.

Мне было интересно, есть ли способ обрезать массив статистики и удалить все элементы, которые не соответствуют условию.

{ 'stats.timestamp': { '$gt': '2022-08-22' } }

Я хочу, чтобы элементы внутри статистики были только теми, у которых есть метка времени > 2022-08-22.

я хочу что-то без агрегата.

Получение данных из формы с помощью JavaScript - краткое руководство
Получение данных из формы с помощью JavaScript - краткое руководство
Получить данные из формы с помощью JS очень просто: вы запрашиваете элемент формы, передаете его конструктору new FormData() и, наконец, получаете...
Пользовательские правила валидации в Laravel
Пользовательские правила валидации в Laravel
Если вы хотите создать свое собственное правило валидации, Laravel предоставляет возможность сделать это. Создайте правило с помощью следующей...
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
3
0
100
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать функцию nodejs, которая выполняется один раз каждый 24 hours и обрезает массив, например:

async function trimUnnecessaryItems(){
await db.model.updateMany({},{$pull: {stats: {timestamp: {$gt': '2022-08-22}}}})
}

я не хочу удалять эту статистику.

EskBejamin 30.08.2022 22:09

но это то, что вы сказали в вопросе - I was wondering if there is a way to trim array of stats and delete all the elements that don't match the condition.

shubham 31.08.2022 05:40
Ответ принят как подходящий

find document and trim array elements that don't match with the condition

Вы можете использовать метод find с проекция, чтобы обрезать массив в зависимости от условия. Для этой функции требуется MongoDB v4.4. Следующий запрос выполняется из mongosh (или mongo оболочки) с использованием данных из сообщения.

db.collection.find(
  { }, 
  { 
      data: { 
          $filter: { 
              input: "$data", 
              cond: { 
                  $gt: [ 
                      { $dateToString: { 
                          format: "%Y-%m-%d", 
                          date: { $toDate: "$$this.timestamp" } 
                      } }, 
                      "2022-08-24"     // <----- the date criteria in YYYY-mm-dd format
                  ] 
              } 
          } 
      } 
  }
)
mongoplayground.net/p/lE_jzHLeFoL, как вы можете видеть здесь, данные не возвращаются.
EskBejamin 31.08.2022 10:07

Это потому, что имя поля массива, которое я использовал, было data вместо stats в запросе - просто измените имя поля и запустите запрос.

prasad_ 31.08.2022 11:47

Можно ли ввести весь документ? так как я хочу вернуть полный документ с вычтенным массивом

EskBejamin 31.08.2022 13:08

Да, но вам нужно указать каждое поле явно. Таким образом, в запросе также включите их: collectionId: 1, createdAt: 1, updatedAt: 1 (1 указывает поле для включения).

prasad_ 31.08.2022 13:29

Я думаю, что для обновления и обрезки вам нужно будет использовать обновление с $filter в совокупности. Я не уверен, есть ли способ пропустить агрегацию, не прибегая к помощи уровня js/другого приложения/скрипта.

db.collection.update({
  "stats.timestamp": {
    "$lte": ISODate("2022-08-22")
  }
},
[
  {
    $set: {
      "stats": {
        $filter: {
          input: "$stats",
          as: "s",
          cond: {
            $gt: [
              "$$s.timestamp",
              ISODate("2022-08-22")
            ]
          }
        }
      }
    }
  }
],
{
  multi: true
})

Вот Детская площадка Монго для справки.

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