Uwzględnij wszystkie istniejące pola i dodaj nowe pola do dokumentu

123

Chciałbym zdefiniować etap agregacji $ projektu, w którym mogę poinstruować go, aby dodał nowe pole i uwzględnił wszystkie istniejące pola, bez konieczności wyszczególniania wszystkich istniejących pól.

Mój dokument wygląda tak, z wieloma polami:

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

Chcę wykonać taką operację agregacji:

[
    {
        $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...
]

Czy jest coś takiego jak słowo kluczowe „uwzględnij wszystkie pola”, którego mogę użyć w tym przypadku, lub inny sposób, aby uniknąć konieczności wyszczególniania każdego pola osobno?

samuelluis
źródło
1
Ta funkcja będzie dostępna w następnej głównej wersji 2.6. Możesz to wypróbować na niestabilnej gałęzi deweloperów - użyj „$$ ROOT”, aby odnieść się do całego przychodzącego dokumentu. Zobacz szczegóły w tym bilecie: jira.mongodb.org/browse/SERVER-5916
Asya Kamsky
1
Ten problem został również poruszony na stackoverflow.com/questions/20497499/… , gdzie znajdują się inne przydatne i różne odpowiedzi.
Vince Bowdren

Odpowiedzi:

168

W 4.2+ możesz użyć $setoperatora potoku agregacji, który jest niczym innym jak aliasem $addFieldsdodanym w 3.4

$addFieldsEtapem jest odpowiednikiem $projectetapie wyraźnie określa, że wszystkie istniejące pola w dokumentach wejściowych i dodaje nowe pola.

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])
stywan
źródło
2
Masz pomysł, jak go używać w sterowniku C #? wydaje się, że nie istnieje
Homam
Nie znam sterownika C #, ale $addFieldsjest nowy w MongoDB 3.4, który jest obsługiwany przez sterownik C # w wersji
2.5+
Szukałem sposobu na zrobienie tego w sterowniku C # i do tej pory wygląda na to, że sposobem na to byłoby użycie czegoś takiegoIAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse
4
Odkryłem, że może nawet zastąpić pole, jeśli podasz tę samą nazwę pola
CME64
79

Możesz użyć $$ ROOT, aby odwołać się do dokumentu głównego. Zachowaj wszystkie pola tego dokumentu w polu i spróbuj go później uzyskać (w zależności od systemu klienta: Java, C ++, ...)

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

        }
    },
    ... //group, match, and whatever...
]
Deka
źródło
17
Ale to stworzy osadzony dokument nazwany documentopcją utworzenia jednego scalonego dokumentu, byłby ładniejszy ...
Alexander Suraphel
2
Czy ktoś zna rozwiązanie umożliwiające przejście przez wszystkie pary klucz-wartość bez tworzenia osadzonego dokumentu?
ugotchi
11
Wstrzymaj oddech. MongoDB 3.4 będzie zawierał etap agregacji $ addFields , który właśnie to robi. Zobacz stackoverflow.com/a/24557029/4653485 .
Jérôme
Wydaje się, że jest to najlepsze obecne rozwiązanie, ponieważ możesz (przynajmniej w JS) użyć operatora rozprzestrzeniania, aby odbudować oryginalny obiekt z nowym custom_fielddołączonym. const newObj = { ...result.document, custom_field: result.custom_field }
ffritz
7

>>> Jest coś takiego jak słowo kluczowe „uwzględnij wszystkie pola”, którego mogę użyć w tym przypadku lub jakieś inne rozwiązanie?

Niestety, nie istnieje operator „uwzględniania wszystkich pól” w operacji agregacji. Jedyny powód, dlaczego, ponieważ agregacja jest głównie tworzona w celu grupowania / obliczania danych z pól kolekcji (suma, średnia itp.) I zwracania wszystkich pól kolekcji, nie jest bezpośrednim celem.

Victoria Malaya
źródło
... ponieważ agregacja jest głównie tworzona w celu grupowania / obliczania danych z pól kolekcji ... Właściwie najlepsza odpowiedź!
felipsmartins
1
masz kolekcję postsz _id, title, body, polubień. Pole polubień to tablica identyfikatorów użytkowników, którym podobał się post. Jak możesz wyświetlić listę wszystkich postów ze wszystkimi _id, title, body, likeCount? Zwrócenie wszystkich pól jest w tym przypadku bezpośrednim celem.
doc_id
3

Od wersji 2.6.4 Mongo DB nie ma takiej funkcji dla $projectpotoku agregacji. Z dokumentów dla $project:

Przechodzi wraz z dokumentami zawierającymi tylko określone pola do następnego etapu potoku. Określone pola mogą być polami istniejącymi z dokumentów wejściowych lub nowo obliczonymi polami.

i

Pole _id jest domyślnie zawarte w dokumentach wyjściowych. Aby dołączyć inne pola z dokumentów wejściowych do dokumentów wyjściowych, musisz jawnie określić włączenie do $ project.

Ghopper21
źródło
2

Aby dodać nowe pola do dokumentu, możesz użyć $addFields

z dokumentów

i do wszystkich pól w dokumencie, których możesz użyć $$ROOT

db.collection.aggregate([

{ "$addFields": { "custom_field": "$obj.obj_field1" } },
{ "$group": {
        _id : "$field1",
        data: { $push : "$$ROOT" }
    }}
])
Deeksha Sharma
źródło
0

zgodnie z odpowiedzią @Deka, dla sterownika c # mongodb 2.5 można uzyskać zgrupowany dokument ze wszystkimi kluczami jak poniżej;

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);
mr.byte
źródło