Условное обновление элементов в запросе mongoose - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть следующий код, и я пытаюсь сделать две вещи. Во-первых, я хочу, чтобы в моем запросе было одно условие, когда он находит значение «originator» в документе, но второй параметр не должен обновляться, если он также находит «owner_id», то же, что и originator.

Вторая часть того, что я пытаюсь сделать, - это только установить / обновить поле - оно передается. Могу ли я использовать троичное выражение, как показано ниже ???

  Contacts.update(
    {
      'originator': profile.owner_id,
      'owner_id': !profile.owner_id
    }, 
    {
      $set: {
        (phoneNumber) ? ('shared.phones.$.phone_number': phoneNumber):null,
        (emailAddress) ? ('shared.emails.$.email_address': emailAddress):null
      }
    }, 
    {
      'multi': true
    },
    function(err) {
      err === null ? console.log('No errors phone updated for contacts.shared') : console.log('Error: ', err);
    }
  ) 

1 Ответ

0 голосов
/ 01 ноября 2018

Вы имеете в виду что-то вроде этого:

var updateBlock = {};
if (phoneNumber)
  updateBlock['shared.phones.$.phone_number'] = phoneNumber;
if (emailAddress)
  updateBlock['shared.email.$.email_address'] = emailAddress;

Contacts.updateMany(
  { 
    "originator": profile.owner_id
    "owner_id": { "$ne": profile.owner_id }
  },
  { "$set": updateBlock },
  function(err, numAffected) {
     // work with callback
  }
)

Это устраняет ваши два «основных» заблуждения, заключающиеся в том, что для «неравенства» в условии запроса требуется оператор $ne, а not выражение ! JavaScript. MongoDB не использует здесь выражения JavaScript для условий запроса.

Вторым «основным» заблуждением является построение «блока обновления» с условными ключами. Это, напротив, «объект JavaScript», который вы создаете отдельно , чтобы указывать только те ключи, которые вы хотите применить.

Однако есть ЕЩЕ ПРОБЛЕМА , в которой вы хотите использовать позиционный оператор $ . Предполагая, что у вас на самом деле есть «массивы» в документе:

{
   "originator": "Bill",
   "owner_id": "Ted",
   "shared": {
     "phones": [ "5555 5555", "4444 4444" ],
     "email": [ "bill@stalyns.org", "bill@example.com" ]
   }
}

Тогда ваша «двойная» новая проблема такова:

  1. Вы должны указать условие запроса, которое соответствует элементу массива «в блоке запроса», чтобы получить «согласованную позицию», в которой необходимо выполнить обновление.

  2. Вы можете только вернуть ONE индекс согласованного массива с помощью оператора позиционного $ и NOT TWO как было бы присуще обновлению такого документа.

По этим (и другим) причинам настоятельно рекомендуется иметь "несколько массивов" в одном документе. Гораздо лучший подход заключается в использовании «единственного» массива и использовании свойств, чтобы указать, какой «тип» записи элемент списка содержит:

{
   "originator": "Bill",
   "owner_id": "Ted",
   "shared": [
     { "type": "phone", "value": "5555 5555" },
     { "type": "phone", "value": "4444 4444" },
     { "type": "email", "value": "bill@stalyns.org" },
     { "type": "email", "value": "bill@example.com" }
   ]
}

Таким образом, вы можете обратиться к «подобранному» элементу для обновления:

// phoneNumberMatch = "4444 4444";
// phoneNumber = "7777 7777";
// emailAddress = null;            // don't want this one
// emailAddressMatch = null;       // or this one
// profile = { owner_id: "Bill" };

var query = {
  "originator": profile.owner_id,
  "owner_id": { "$ne": profile.owner_id },
  "shared": {
    "$elemMatch": {
      "type": (phoneNumber) ? "phone" : "email",
      "value": (phoneNumber) ? phoneNumberMatch : emailAddressMatch
    }
  }
};

var updateBlock = {
  "$set": {
    "shared.$.value": (phoneNumber) ? phoneNumber : emailAddress
  }
};

Contacts.updateMany(query, updateBlock, function(err, numAffected) {
  // work with callback
})

В таком случае и с «двоичным» выбором вы «можете» использовать троичные условия в конструкции, поскольку вы не полагаетесь на «именование ключей» в конструкции.

Если вы хотите, чтобы "либо, либо действительно оба" предоставили значения в комбинации, тогда вам нужно немного более сложное утверждение:

// phoneNumberMatch = "5555 5555";
// phoneNumber = "7777 7777";
// emailAddress = "bill@nomail.com";
// emailAddressMatch = "bill@example.com";
// profile = { owner_id: "Bill" };

var query = {
  "originator": profile.owner_id,
  "owner_id": { "$ne": profile.owner_id },
  "$or": []
};

var updateBlock = { "$set": {} };
var arrayFilters = [];

if (phoneNumber) {
  // Add $or condition for document match
  query.$or.push(
    {
      "shared.type": "phone",
      "shared.value": phoneNumberMatch
    }
  );

  // Add update statement with named identifier
  updateBlock.$set['shared.$[phone].value'] = phoneNumber;

  // Add filter condition for named identifier
  arrayFilters.push({
    "phone.type": "phone",
    "phone.value": phoneNumberMatch
  })
}

if (emailAddress) {
  // Add $or condition for document match
  query.$or.push(
    {
      "shared.type": "email",
      "shared.value": emailAddressMatch
    }
  );

  // Add update statement with named identifier
  updateBlock.$set['shared.$[email].value'] = emailAddress;

  // Add filter condition for named identifier
  arrayFilters.push({
    "email.type": "email",
    "email.value": emailAddressMatch
  })
}

Contacts.updateMany(query, updateBlock, arrayFilters, function(err, numAffected) {
  // work with callback
})

Здесь, конечно, следует отметить, что синтаксис с позиционной фильтрацией $[<identifier>] от MongoDB 3.6 и выше требуется для того, чтобы создать несколько элементов массива в одном обновить заявление.

То же самое относится и к «исходной» структуре, которую я впервые описал, используя «множественные» массивы в документах вместо именованных свойств в «единственном» массиве, как в приведенных выше примерах:

var query = {
  "originator": "Bill",
  "owner_id": { "$ne": "Bill" },
  "$or": []
};

var updateBlock = { "$set": {} };
var arrayFilters = [];

if (phoneNumber) {
  query.$or.push({
    "shared.phones": phoneNumberMatch
  });

  updateBlock.$set['shared.phones.$[phone]'] = phoneNumber;

  arrayFilters.push({
    "phone": phoneNumberMatch
  });
}

if (emailAddress) {
  query.$or.push({
    "shared.email": emailAddressMatch
  });

  updateBlock.$set['shared.email.$[email]'] = emailAddress;

  arrayFilters.push({
    "email": emailAddressMatch
  });
}

Contacts.updateMany(query, updateBlock, arrayFilters, function(err, numAffected) {
  // work with callback
})

Конечно, если у вас вообще нет массивов (в опубликованном вопросе отсутствует какой-либо пример документа), то позиционные совпадения даже не нужны ни в какой форме, но вы все же «условно» конструируете «ключи» объекта JavaScript через строительные кодовые блоки. Вы не можете «условно» указать «ключ» в JSON-подобной нотации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...