Включіть усі існуючі поля та додайте нові документи до документа


123

Я хотів би визначити етап агрегації $ проекту, де я можу доручити йому додати нове поле та включити всі існуючі поля, не перераховуючи всі існуючі поля.

Мій документ виглядає приблизно так, з багатьма полями:

{
    obj: {
        obj_field1: "hi",
        obj_field2: "hi2"
    },
    field1: "a",
    field2: "b",
    ...
    field26: "z"
}

Я хочу зробити операцію агрегації так:

[
    {
        $project: {
            custom_field: "$obj.obj_field1",
            //the next part is that I don't want to do
            field1: 1,
            field2: 1,
            ...
            field26: 1
        }
    },
    ... //group, match, and whatever...
]

Чи є щось на кшталт ключового слова "включити всі поля", яке я можу використовувати в цьому випадку, чи якийсь інший спосіб уникнути необхідності перераховувати кожне поле окремо?


1
Ця функція з'явиться в наступному великому випуску 2.6. Ви можете спробувати його на нестабільній гілці розробників - використовуйте "$$ ROOT" для позначення всього вхідного документа. Деталі дивіться у цьому квитку: jira.mongodb.org/browse/SERVER-5916
Ася Камський

1
Це питання також порушене на сайті stackoverflow.com/questions/20497499/… , з іншими корисними та різними відповідями.
Вінс Боудрен

Відповіді:


168

У 4.2+ ви можете використовувати $setоператора конвеєрного конвеєра, який є не що інше, як псевдонім, $addFieldsдоданий у 3.4

$addFieldsСтадія еквівалентна $projectстадії , що явно вказує всі існуючі поля введення документів і додає нові поля.

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])

2
Будь-яка ідея, як його використовувати в драйвері C #? Здається, його не існує
Хомам

Я не знайомий з драйвером C #, але він $addFieldsє новим у MongoDB 3.4, який підтримується драйвером C # версії 2.5+
styvane

Я шукав спосіб зробити це в драйвері C #, і поки що це виглядає як спосіб зробити це, використовуючи щось на кшталтIAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse

4
Я виявив, що він навіть може замінити поле, якщо вказати те саме ім’я поля
CME64

79

Ви можете використовувати $$ ROOT для посилання на кореневий документ. Зберігайте всі поля цього документа у полі та намагайтеся отримати його після цього (залежно від вашої клієнтської системи: Java, C ++, ...)

 [
    {
        $project: {
            custom_field: "$obj.obj_field1",
            document: "$$ROOT"

        }
    },
    ... //group, match, and whatever...
]

17
Але це створить вбудований документ, який називається documentопцією для створення одного об'єднаного документа, було б приємніше ...
Олександр Сурафель

2
Хтось знає про рішення пройти через усі пари ключових значень без створення вбудованого документа?
ugotchi

11
Затримайте дихання. MongoDB 3.4 поставиться на етапі агрегації $ addFields, який робить саме це. Дивіться stackoverflow.com/a/24557029/4653485 .
Jérôme

Це здається найкращим поточним рішенням, оскільки ви можете (принаймні, в JS) потім використовувати оператор розведення для відновлення свого оригінального об'єкта з новим custom_fieldдоданим. const newObj = { ...result.document, custom_field: result.custom_field }
ffritz

7

>>> Існує щось на кшталт ключового слова "включити всі поля", яке я можу використовувати в цьому випадку чи якесь інше рішення?

На жаль, не існує жодного оператора, який би "включав усі поля" в операцію агрегації. Єдина причина, чому саме тому, що агрегація в основному створюється для групування / обчислення даних з полів збору (сума, середня кількість тощо) та повернення всіх полів колекції, не є прямим призначенням.


... тому що агрегація в основному створюється для групування / обчислення даних із полів збору ... Найкраща відповідь насправді!
felipsmartins

1
у вас є колекція postsз полями _id, назва, тіло, подобається поля. Поле «лайки» - це масив користувача _id, якому подобається публікація. Як ви могли перелічити всі повідомлення з усіма _id, заголовком, тілом, якCount? Повернення всіх полів є прямою метою у цьому випадку.
doc_id

3

Станом на версію 2.6.4, DB DB не має такої особливості для $projectконвеєрного конвеєра. З документів для $project:

Проходить по документах із лише вказаними полями до наступного етапу трубопроводу. Зазначені поля можуть бути існуючими полями з вхідних документів або знову обчисленими полями.

і

Поле _id за замовчуванням міститься у вихідних документах. Для включення інших полів із вхідних документів у вихідні документи потрібно чітко вказати включення до $ project.


2

Щоб додати нові документи до свого документа, ви можете використовувати $addFields

від док

і до всіх полів у вашому документі ви можете використовувати $$ROOT

db.collection.aggregate([

{ "$addFields": { "custom_field": "$obj.obj_field1" } },
{ "$group": {
        _id : "$field1",
        data: { $push : "$$ROOT" }
    }}
])

0

Відповідно до відповіді @Deka, для драйвера c # mongodb 2.5 ви можете отримати згрупований документ із усіма клавішами, як показано нижче;

var group = new BsonDocument
{
 { "_id", "$groupField" },
 { "_document", new BsonDocument { { "$first", "$$ROOT" } } }
};

ProjectionDefinition<BsonDocument> projection = new BsonDocument{{ "document", "$_document"}};
var result = await col.Aggregate().Group(group).Project(projection).ToListAsync();

// For demo first record 
var fistItemAsT = BsonSerializer.Deserialize<T>(result.ToArray()[0]["document"].AsBsonDocument);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.