Как $вытащить mongodb, если у вас есть странные данные внутри массива?

#node.js #mongodb #mongoose

Вопрос:

Итак, в основном у меня есть эти данные

 {
  company: {
    subscriptions: [
      {
        "name": "test1",
        "updatedAt": ISODate("2021-10-19T06:40:33.583Z")
      },
      {
        "name": "test2",
        "updatedAt": ISODate("2021-10-19T06:40:33.583Z")
      },
      {
        "services": {
          "1": {
            "createdAt": ISODate("2021-10-19T06:40:33.583Z"),
            "updatedAt": ISODate("2021-10-19T06:40:33.583Z")
          }
        },
        "updatedAt": ISODate("2021-10-19T06:40:33.583Z")
      }
    ]
  }
}
 

В настоящее время я не знаю, как эти данные вставляются в коллекцию.

Странные данные вот эти.

 {
        "services": {
          "1": {
            "createdAt": ISODate("2021-10-19T06:40:33.583Z"),
            "updatedAt": ISODate("2021-10-19T06:40:33.583Z")
          }
        },
        "updatedAt": ISODate("2021-10-19T06:40:33.583Z")
      }
 

Как я могу использовать mongodb $pull, чтобы удалить этот внутренний массив подписок?

Ответ №1:

Запрос 1

  • $pull, если у участника нет поля с именем name, оно удаляется

Тестовый код здесь

 db.collection.updateMany({},
{
  $pull: {
    "company.subscriptions": {
      name: {
        "$exists": false
      }
    }
  }
})
 

Запрос 2

  • альтернативный способ с трубопроводом
  • это удаляет элемент массива, если в нем нет поля name (или имя равно false/null).
  • службы, которые вы не хотите удалять, не имеют имени, поэтому они будут отфильтрованы

для обновления конвейера требуется MongoDB >= 4.2

Тестовый код здесь

 db.collection.updateMany({},
[
  {
    "$set": {
      "company.subscriptions": {
        "$filter": {
          "input": "$company.subscriptions",
          "cond": "$this.name"
        }
      }
    }
  }
])
 

Если ваш метод updateMany не принимает конвейер, вы можете запустить его как команду as

 db.runCommand(
   {
      update: "yourCollection",
      updates: [
         {
           q: { },
           u: [
               {
                 "$set": {
                  "company.subscriptions": {
                    "$filter": {
                      "input": "$company.subscriptions",
                       "cond": "$this.name"
                   }
              }}}
           ],
           multi: true
         }
      ],
      ordered: false
   }
)
 

Комментарии:

1. Я получил эту ошибку Invalid query: Line 1: Expected '(' instead of 'M' , если использую updateMany

2. вы могли бы сделать это также с помощью фильтров массива и $pull . Вот руководство , но самое важное-это ссылка , в которой есть все типы операторов с примерами

3. Большое вам спасибо за ссылки и ваши ответы

4. этот код работает в оболочке, в nodejs, возможно, его небольшая разница, в способе вызова, я ищу его

5. Я уже нашел решение, большое вам спасибо

Ответ №2:

Основываясь на ответе @Takis_, я нашел решение. Вот что я сделал.

 const cursor = await Company.find({
    $and: [
      {
        "subscriptions": { $exists: true, $ne: [] }
      }
    ]
  }).cursor();


  await cursor.eachAsync(async company => {
    let isUpdate = false;

    const found = find(company.subscriptions, subscription => subscription.name === undefined);

    if (!found) return

    try {
      const res = await Company.updateOne(
        {
          "_id": mongoose.Types.ObjectId(company._id),
        },
        {
          $pull: { subscriptions: { name: { $exists: false } } }
        }
      );
    } catch(err) {
      log(`ERROR removing subscription entry for company ${company.name} - ${company._id}`);
    }
  })
 

Хотя у @Takis есть правильный ответ, этот со своей стороны работает на меня