MongoDB - upsert с использованием списков - PullRequest
5 голосов
/ 29 июня 2010

Я новичок в MongoDB и хотел спросить, как написать команду обновления, включающую upsert и list.

В основном я хочу сделать что-то вроде этого:

{"_id" : ObjectId("4c28f62cbf8544c60506f11d"),
"some_other_data":"goes here",
"trips": [
    {"name": "2010-05-10",
     "loc": [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
        {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}]
    },
    {"name": "2010-05-08",
     "loc": [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"},
        {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
        {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}]
    }
]}

Обратите внимание, что:

  • Вы указываете название поездки и текущее местоположение
  • Если поездка еще не существует, она нужно создать
  • trips.name должен быть уникальным, чтобы если он существует, вы добавляете массив местоположений

Это запрос, который я написал, комбинируя позиционный оператор с $ push.

    db.mycollection.update({"application_id": "MyTestApp", 
                            "trips.name": "2010-05-10"},
                           {$push: {'trips.$.loc': {"lat":11, "lng":11} }}, 
                           true);

Но это приводит к таким данным:

> db.mycollection.find({"application_id":"MyTestApp"})          
{ "_id" : ObjectId("4c29044ebf8544c60506f11f"), 
"application_id" : "MyTestApp", 
"trips" : { "$" : { "loc" : [ { "lat" : 11, "lng" : 11 } ] }, 
"name" : "2010-05-10" } 
}

Вы можете видеть, что

  • "поездки" не является массивом
  • буквально взял "$" и создал ключ с этим (дох!)

До сих пор я был очень доволен MongoDB, но определенно крутая кривая обучения с написанием сложных запросов.

Любые отзывы будут оценены.

Заранее спасибо, Amie

Ответы [ 2 ]

4 голосов
/ 29 июня 2010

Нельзя смешивать позиционный оператор ("$") и upsert;«$» будет обрабатываться как имя поля во время вставки.Вы не можете сделать это для новых документов, только для существующих.

Я предложил структуру, похожую на эту:

{"_id" : ObjectId("4c28f62cbf8544c60506f11d"),
"some_other_data":"goes here",
"trips": { 
    "2010-05-10":
       [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
        {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}],
    "2010-05-08": 
       [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"},
        {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
        {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}]
    }
}

Тогда вы можете выпустить обновление, подобное этому:

db.mycollection.update({application_id: "MyTestApp", "trips.2010-05-10":{$exists:true}},
                       {$push: {"trips.2010-05-10": {lat:11, lng:11} }}, 
                       true);

приводит к тому, что это вставляется.

> db.mycollection.find()
{ "_id" : ObjectId("4c2931d17b210000000045f0"), 
    "application_id" : "MyTestApp", 
    "trips" : { "2010-05-10" : [ { "lat" : 11, "lng" : 11 } ] } }

и повторный запуск дает вам следующее:

> db.mycollection.find()
{ "_id" : ObjectId("4c2932db7b210000000045f2"), 
    "application_id" : "MyTestApp", 
    "trips" : { "2010-05-10" : 
        [ { "lat" : 11, "lng" : 11 }, 
          { "lat" : 11, "lng" : 11 } ] } }
1 голос
/ 29 июня 2010

ИЗМЕНЕНО, ЧТОБЫ ВКЛЮЧИТЬ ПРАВИЛЬНОЕ РЕШЕНИЕ

Это именно та проблема, с которой я столкнулся при изучении Mongo - вы ищете оператор $addToSet ( см. Документы здесь ), который используется с командой update в сочетании с позиционным оператором $, который вы использовали.

$ addToSet

{$ addToSet: {field: value}}

Добавляет значение в массив, только если его уже нет в массиве.

Таким образом, запрос становится (db.stack - это коллекция, которую я использовал для целей тестирования), пример запускается вследуйте:

db.stack.update({ "trips.name":"2010-05-10" }, 
                { $addToSet: { "trips.$.loc":{"lat":11, "lng":12} } }
               );

TEST RUN (с некоторыми сокращениями для пробелов элементов, которые не важны):

#### YOUR ITEM IN THE DB
> db.stack.find({"trips.name":"2010-05-10"})
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [
    { "name" : "2010-05-10",
        "loc" : [ {
                "lat" : 21.321231,
                "lng" : 16.8783234,
                "updated_at" : "Mon May 10 2010 15:24:35"
            }, { "lat" : 21.321231,
                "lng" : 16.8783234,
                "updated_at" : "Mon May 10 2010 15:24:24"
            } ] },
    { "name" : "2010-05-08",
        "loc" : [ ... ]
    } ] }
#### SUCCESSFULLY ADDS ITEM TO PROPER ARRAY
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}});
> db.stack.findOne()
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here",
    "trips" : [
        { "loc" : [
                { "lat" : 21.321231,
                    "lng" : 16.8783234,
                    "updated_at" : "Mon May 10 2010 15:24:35"
                }, { "lat" : 21.321231,
                    "lng" : 16.8783234,
                    "updated_at" : "Mon May 10 2010 15:24:24"
                }, { "lat" : 11,
                    "lng" : 11
                }
            ], "name" : "2010-05-10"
        },
        { "name" : "2010-05-08",
            "loc" : [ ...  ]
        } ] }
#### ON REPEAT RUN DOESN'T ADD NEW ELEMENT
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}});
> db.stack.findOne()
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here",
    "trips" : [ {
            "loc" : [
                { "lat" : 21.321231,
                    "lng" : 16.8783234,
                    "updated_at" : "Mon May 10 2010 15:24:35"
                }, { "lat" : 21.321231,
                    "lng" : 16.8783234,
                    "updated_at" : "Mon May 10 2010 15:24:24"
                }, { "lat" : 11,
                    "lng" : 11
                }
            ], "name" : "2010-05-10"
        },
        { "name" : "2010-05-08",
            "loc" : [ ...  ]
        } ] }
#### BUT WILL CORRECTLY ADD ANOTHER ELEMENT TO THE SAME ARRAY IF IT'S NOT PRESENT
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":12}}});
> db.stack.findOne()
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here",
    "trips" : [
        { "loc" : [
                { "lat" : 21.321231,
                    "lng" : 16.8783234,
                    "updated_at" : "Mon May 10 2010 15:24:35"
                }, { "lat" : 21.321231,
                    "lng" : 16.8783234,
                    "updated_at" : "Mon May 10 2010 15:24:24"
                }, { "lat" : 11,
                    "lng" : 11
                }, { "lat" : 11,
                    "lng" : 12
                }
            ], "name" : "2010-05-10"
        },
        { "name" : "2010-05-08",
            "loc" : [ ... ]
    } ] }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...