получить _id документа mongodb, который мы вставляем, если он не существует, и обновляем, если он уже существует

У меня есть коллекция подписчиков с уникальным индексом {LISTID:1, EMAIL:1}. Я хочу вставить документ, если он не существует, и обновить его, если он уже существует, но в любом случае я хочу получить _id документа, независимо от того, вставлен он или обновлен.

$mongo = new Mongo();
$db = $mongo->test; 
$collection = $db->subscribers;
$criteria = array('LISTID' => 86, 'EMAIL' => '[email protected]');
$data = array('LISTID' => 86, 'EMAIL' => '[email protected]', 'FNAME' => 'Oleg');
$result = $collection->update($criteria, $data, array('fsync' => true, 'upsert' => true));    
var_dump($data);
var_dump($result);

Если документ вставлен, я получаю результат:

array
  'LISTID' => int 86
  'EMAIL' => string '[email protected]' (length=21)
  'FNAME' => string 'Oleg' (length=4)

array
          'updatedExisting' => boolean false
          'upserted' => 
            object(MongoId)[6]
              public '$id' => string '506446e4e0dae94a0bd25d06' (length=24)
          'n' => int 1
          'connectionId' => int 10
          'fsyncFiles' => int 7
          'err' => null
          'ok' => float 1

Но если он обновлен, я получаю результат без _id:

array
  'LISTID' => int 86
  'EMAIL' => string '[email protected]' (length=21)
  'FNAME' => string 'Oleg' (length=4)
array
  'updatedExisting' => boolean true
  'n' => int 1
  'connectionId' => int 10
  'fsyncFiles' => int 7
  'err' => null
  'ok' => float 1

Подскажите, пожалуйста, как получить _id, даже если запись обновлена, но не вставлена?


person Oleg    schedule 27.09.2012    source источник


Ответы (2)


Проблема здесь в том, что MongoCollection.update() не вернет _id (точно так же, как MongoCollection.insert()

Если в базе данных нет совпадений и у вас есть upsert=>true, вы получите id внутри объекта upserted. Нет, если есть соответствие.

Если вы хотите обновить или вставить отдельный документ, вы можете использовать команду findAndModify с upsert (помощник добавлен в версии 1.3.0-бета)

$mongo = new Mongo();
$db = $m->mydatabase;
$query = array('LISTID' => 86, 'EMAIL' => '[email protected]');
$update = array('$set' => array('LISTID' => 86, 'EMAIL' => '[email protected]', 'FNAME' => 'Oleg') );

$result = $db->command(
  array(
    "findandmodify" => "test", / /name of collection
    "query" => $query,
    "update" => $update,
    'upsert' => 1
  )
);

Результат в обеих ситуациях будет разным, смотрите здесь:

Запись найдена, обновлена:

Array
(
    [value] => Array
        (
            [_id] => MongoId Object
                (
                    [$id] => 506470963e20d69457000000
                )

            [LISTID] => 86
            [EMAIL] => [email protected]
        )

    [lastErrorObject] => Array
        (
            [updatedExisting] => 1
            [n] => 1
        )

    [ok] => 1
)

Запись не найдена, вставлено:

Array
(
    [value] => 
    [lastErrorObject] => Array
        (
            [updatedExisting] => 
            [n] => 1
            [upserted] => MongoId Object
                (
                    [$id] => 5064708213995e82a829753e
                )

        )

    [ok] => 1
)

Вам нужно будет получить _id в двух разных местах в зависимости от того, вставил ли или обновил документ findAndModify.

person Gianfranco P.    schedule 27.09.2012

Измените переменную $data на $set и повторите попытку.

$data =  array('$set' => array('LISTID' => 86, 'EMAIL' => '[email protected]', 'FNAME' => 'Oleg'));
person Justin John    schedule 27.09.2012
comment
Это не работает. Результат тот же: array 'updatedExisting' => boolean true 'n' => int 1 'connectionId' => int 10 'fsyncFiles' => int 7 'err' => null 'ok' => float 1 - person Oleg; 27.09.2012
comment
Что будет результатом var_dump($collection->findOne(array('LISTID' => 86, 'EMAIL' => '[email protected]'))); - person Justin John; 27.09.2012
comment
Что-то вроде этого: массив 'EMAIL' => строка '[email protected]' (длина = 21) 'FNAME' => строка 'Олег' (длина = 4) 'LISTID' => int 86 '_id' => объект (MongoId)[6] общедоступный '$id' => строка '50645fe9e0dae94a0bd25d07' (длина = 24) - person Oleg; 27.09.2012
comment
Он возвращает документ, если такой документ уже существует. Но тогда документ существует, и эта операция его обновляет, id не возвращается. - person Oleg; 27.09.2012
comment
Попробуйте print_r $criteria и $data после обновления и убедитесь, что в нем есть [_id]. Я не уверен в этом. - person Justin John; 27.09.2012
comment
$data не содержит _id после этой операции. - person Oleg; 27.09.2012
comment
Вы знаете, в чем проблема? - person Oleg; 27.09.2012
comment
Извините, я не знаю точно больше об этом. Я думаю, что только вставка получит идентификатор монго, а не в случае обновления. - person Justin John; 27.09.2012