Получение количества элементов вложенного документа на индекс внутри массива и обновление ключа вложенного документа - вложенный документ в массиве (IN MONGODB)

Как получить количество элементов вложенного документа внутри массива и как обновить ключ вложенного документа в MongoDB

Например, весь документ хранится в mongodb:

{
    "CompanyCode" : "SNBN",
    "EventCode" : "ET00008352",
    "EventName" : "Sunburn Presents Avicii India Tour",
    "TktDetail" : [ 
        {
            "Type" : "Category I",
            "Qty" : {
                "10-Dec" : {
                    "value" : 58
                },
                "11-Dec" : {
                   "value" : 83
                },
                "12-Dec" : {
                   "value" : 100
                } 
            }
        }, 
        {
            "Type" : "Category II",
            "Qty" : {
                "10-Dec" : {
                   "value" : 4
                },
                "11-Dec" : {
                    "value" : 7
                },
                "12-Dec" : {
                    "value" : 8
                }
            }
        }, 
        {
            "Type" : "PRICE LEVEL 1",
            "Qty" : {
                "11-Dec" : {
                    "value" : 2
                }
            }
        }, 
        {
            "Type" : "CatIV",
            "Qty" : {
                "18-Dec" : {
                    "value" : 20
                }
            }
        }
    ],
    "TransDate" : [ 
        "10-Dec-2013", 
        "11-Dec-2013", 
        "12-Dec-2013", 
    ],
    "VenueCode" : "SNBN",
    "VenueName" : "Sunburn",
    "_id" : ObjectId("52452db273b92012c41ad612")
}

Здесь TktDetail представляет собой массив, внутри которого находится поддокумент Qty, содержащий несколько элементов. Я хочу знать, как получить количество элементов внутри Qty на индекс?

Например, 0-й индекс массива TktDetail содержит 1 поддокумент Qty, который также имеет количество элементов 3, тогда как 3-й индекс имеет количество элементов 1 в поддокументе Qty.

Если я хочу обновить ключ поддокумента, например, я хочу обновить дату в Qty с «10 декабря» на «10 декабря 2013 года», как это возможно?

Заранее спасибо,жду ответа как можно скорее..


person Suraj Mishra    schedule 28.02.2014    source источник
comment
Кто-то (пока не я) только что проголосовал за вас, потому что вы не отформатировали свой блок данных, как сайт просит вас сделать. Также НЕ ВЫДЕЛЯЙТЕ все, что выделено жирным шрифтом. Примечание на будущее. Но теперь вы можете получить помощь.   -  person Neil Lunn    schedule 28.02.2014
comment
Теперь. Ваш вопрос (уточните), вы хотите обновить значения в поддокументах в разделе Кол-во. Верно?   -  person Neil Lunn    schedule 28.02.2014
comment
Спасибо, Нил, за совет для будущей заметки. Я не хочу обновлять поле значения внутри Qty, я хочу обновить имя ключа внутри Qty, которое хранится в массиве TktDetail, например: если это 10-Dec, то я хочу обновить его как 10-Dec- 2013.   -  person Suraj Mishra    schedule 28.02.2014
comment
Как и я хочу знать, как я могу получить количество элементов внутри Qty на индекс, Qty 0-го индекса имеет 3 в качестве счетчика, Qty 3-го индекса имеет 1 в качестве счетчика, таким образом?   -  person Suraj Mishra    schedule 28.02.2014


Ответы (1)


Итак, во-первых, вы на самом деле задали два вопроса: "как мне получить количество элементов под Qty?" и "как я могу изменить имена?". Теперь, хотя обычно они не связаны друг с другом, я буду относиться к ним как к одному и тому же.

Что вам нужно сделать, так это изменить схему, и при этом я позволю вам получить количество элементов, а также посоветую вам изменить имена этих полей. В частности, вам нужна такая схема:

"TktDetail" : [ 
    {
        "Type" : "Category I",
        "Qty" : [
            { "date": ISODate("2013-12-10T00:00:00.000Z") , "value" : 58  },
            { "date": ISODate("2013-12-11T00:00:00.000Z"), "value" : 83  },
            { "date": ISODate("2013-12-01T00:00:00.000Z"), "value" : 100 },
        ]
    },

Все кровавые подробности находятся в моем ответе здесь на аналогичный вопрос. Но основная проблема заключается в том, что когда вы используете вложенные документы так, как вы это делаете, вы теряете свои шансы на выполнение каких-либо осмысленных операций запроса, поскольку для получения доступа к каждому элементу вы должны< /strong> укажите полный путь, чтобы туда добраться.

Этот ответ содержит более подробную информацию, но дело в том, что вам действительно нужен массив. Компромисс: обновлять немного сложнее, особенно если учесть, что у вас есть вложенные массивы, но гораздо проще добавлять и гораздо проще запрашивать.

Кроме того, измените свои даты на даты, а не на не строки. Строки не подходят для сравнения внутри MongoDB. Когда они установлены как правильные даты BSON (отметив, что я обрезал их до начала дня), вы можете сравнивать, запрашивать диапазоны и делать полезные вещи. Код вашего приложения будет счастлив, так как драйвер вернет настоящий объект даты, а не то, что вам придется манипулировать "в обоих направлениях".

Итак, как только вы прочитали, поняли и реализовали это, приступайте к подсчету:

db.collection.aggregate([

    // Unwind the TktDetail array to de-normalize
    {"$unwind": "$TktDetail"},

    // Also Unwind the Qty array
    {"$unwind": "$Qty" },

    // Get some group information and count the entries
    {"$group": { 
        "_id": {
            "_id": "$_id,
            "EventCode": "$EventCode",
            "Type": "$TktDetail.Type"
        },
        "Qty": {"$sum": 1 }
    }},

    // Project nicely
    {"$project": { 
        "_id": 0,
        "EventCode": "$_id.EventCode",
        "Type: "$_id.Type",
        "Qty": 1,
    }},

    // Let's even sort it 
    {"$sort": { "EventCode": 1, "Qty" -1 }}

])

Это позволило нам получить количество элементов в Qty для каждого EventCode по Type с Qty упорядоченным от большего к меньшему.

И это невозможно в вашей текущей схеме без загрузки и обхода каждого документа в коде.

Итак, есть дело. Теперь, если вы хотите проигнорировать это и просто изменить имена ключей поддокумента, вам нужно будет удалить ключ и базовый документ и заменить его на новое имя ключа, используя update:

db.collection.update(
    { EventCode: "ET00008352"},
    { $unset:{ "TktDetail.0.Qty.10-Dec": "" }}
)

db.collection.update(
    { EventCode: "ET00008352"},
    { $set:{ "TktDetail.0.Qty.10-Dec-2013": { value: 58 } }}
)

И вам нужно будет сделать это для каждого элемента, который у вас есть.

Таким образом, вы либо выполняете это преобразование схемы, либо иным образом выполняете много работы, чтобы изменить ключи. Что касается меня, я бы сделал это правильно и только один раз, чтобы потом не столкнуться со следующей проблемой.

person Neil Lunn    schedule 28.02.2014
comment
Я очень признателен вам за ваш ответ, но первое решение, в котором вы попросили меня изменить схему коллекции, создаст проблему в будущем при обновлении с использованием $ (позиционный оператор), потому что оно не поддерживается более чем на 1 уровне, и Qty будет быть на 2-м уровне, по этой причине я рассматривал его Qty как поддокумент вместо вложенного массива. - person Suraj Mishra; 28.02.2014
comment
Во-вторых, это известное решение, которое я не могу использовать, потому что хочу пройтись по Qty, не зная имен ключей, и обновить его. - person Suraj Mishra; 28.02.2014
comment
@SurajMishra Я хорошо осведомлен о проблемах с позиционными обновлениями, поэтому я сказал, что это может быть несколько сложно, но не невозможно. Если что-нибудь, единственным элементом, который должен рассматриваться как вложенный документ в этой структуре, будет часть TktDetail, которая усложняет некоторые другие операции, но удаляет позиционное обновление. проблема. Это проблема наименьшего пути и, следовательно, лучшее место. Даже если вы знаете, что вам нужно делать с $set и $unset, другого пути нет. Если вам нужно лучше объяснить измененную структуру, я могу это сделать. - person Neil Lunn; 28.02.2014