Açıklama
Bir dizideki her öğe için yeni bir belge oluşturur.
Yeni dokümanlar, girişten alınan tüm alanların yanı sıra dizideki farklı bir öğeyi içerir. Dizi öğesi, alias verilen değere depolanır ve aynı alan adına sahip önceden var olan değerlerin üzerine yazılabilir.
İsteğe bağlı olarak index_field bağımsız değişkeni belirtilebilir. Mevcut olduğunda, çıkış belgelerinde öğenin kaynak dizideki sıfır tabanlı dizinini içerir.
Bu aşama, birçok SQL sisteminde CROSS JOIN UNNEST(...)'ya benzer şekilde çalışır.
Örnekler
Node.js
const userScore = await db.pipeline()
.collection("/users")
.unnest(field("scores").as("userScore"), /* index_field= */ "attempt")
.execute();
Davranış
Takma ad ve dizin alanı
alias ve isteğe bağlı index_field, giriş dokümanında alanlar zaten varsa orijinal alanların üzerine yazar. index_field sağlanmazsa çıkış belgelerinde bu alan yer almaz.
Örneğin, aşağıdaki koleksiyon için:
Node.js
await db.collection("users").add({name: "foo", scores: [5, 4], userScore: 0});
await db.collection("users").add({name: "bar", scores: [1, 3], attempt: 5});
unnest aşaması, kullanıcı başına her bir puanı ayıklamak için kullanılabilir.
Node.js
const userScore = await db.pipeline()
.collection("/users")
.unnest(field("scores").as("userScore"), /* index_field= */ "attempt")
.execute();
Bu durumda, hem userScore hem de attempt öğesinin üzerine yazılır.
{name: "foo", scores: [5, 4], userScore: 5, attempt: 0}
{name: "foo", scores: [5, 4], userScore: 4, attempt: 1}
{name: "bar", scores: [1, 3], userScore: 1, attempt: 0}
{name: "bar", scores: [1, 3], userScore: 3, attempt: 1}
Diğer örnekler
Swift
let results = try await db.pipeline() .database() .unnest(Field("arrayField").as("unnestedArrayField"), indexField: "index") .execute()
Kotlin
val results = db.pipeline() .database() .unnest(field("arrayField").alias("unnestedArrayField"), UnnestOptions().withIndexField("index")) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .database() .unnest(field("arrayField").alias("unnestedArrayField"), new UnnestOptions().withIndexField("index")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field from google.cloud.firestore_v1.pipeline_stages import UnnestOptions results = ( client.pipeline() .database() .unnest( Field.of("arrayField").as_("unnestedArrayField"), options=UnnestOptions(index_field="index"), ) .execute() )
Java
Pipeline.Snapshot results = firestore .pipeline() .database() .unnest("arrayField", "unnestedArrayField", new UnnestOptions().withIndexField("index")) .execute() .get();
Go
snapshot := client.Pipeline(). Database(). UnnestWithAlias("arrayField", "unnestedArrayField", firestore.WithUnnestIndexField("index")). Execute(ctx)
Dizi Olmayan Değerler
Giriş ifadesi bir dizi olmayan bir değer olarak değerlendirilirse bu aşama, belirtilmişse index_field değeri NULL olarak ayarlanmış giriş belgesini olduğu gibi döndürür.
Örneğin, aşağıdaki koleksiyon için:
Node.js
await db.collection("users").add({name: "foo", scores: 1});
await db.collection("users").add({name: "bar", scores: null});
await db.collection("users").add({name: "qux", scores: {backupScores: 1}});
unnest aşaması, kullanıcı başına her bir puanı ayıklamak için kullanılabilir.
Node.js
const userScore = await db.pipeline()
.collection("/users")
.unnest(field("scores").as("userScore"), /* index_field= */ "attempt")
.execute();
Bu işlem, attempt değeri NULL olarak ayarlanmış aşağıdaki belgeleri oluşturur.
{ name: "foo", scores: 1, attempt: null }
{ name: "bar", scores: null, attempt: null }
{ name: "qux", scores: { backupScores: 1 }, attempt: null }
Boş dizi değerleri
Giriş ifadesi boş bir dizi olarak değerlendirilirse bu giriş dokümanı için doküman döndürülmez.
Örneğin, aşağıdaki koleksiyon için:
Node.js
await db.collection("users").add({name: "foo", scores: [5, 4]});
await db.collection("users").add({name: "bar", scores: []});
unnest aşaması, kullanıcı başına her bir puanı ayıklamak için kullanılabilir.
Node.js
const userScore = await db.pipeline()
.collection("/users")
.unnest(field("scores").as("userScore"), /* index_field= */ "attempt")
.execute();
Bu işlem, çıkışta bar kullanıcısı eksik olan aşağıdaki belgeleri oluşturur.
{name: "foo", scores: [5, 4], userScore: 5, attempt: 0}
{name: "foo", scores: [5, 4], userScore: 4, attempt: 1}
Boş diziler içeren dokümanları da döndürmek için iç içe yerleştirilmemiş değeri bir diziye sarabilirsiniz. Örneğin:
Node.js
const userScore = await db.pipeline()
.collection("/users")
.unnest(
conditional(
equal(field("scores"), []),
array([field("scores")]),
field("scores")
).as("userScore"),
/* index_field= */ "attempt")
.execute();
Bu işlem artık kullanıcı bar ile dokümanı döndürecek.
{name: "foo", scores: [5, 4], userScore: 5, attempt: 0}
{name: "foo", scores: [5, 4], userScore: 4, attempt: 1}
{name: "bar", scores: [], userScore: [], attempt: 0}
Diğer örnekler
Node.js
// Input // { identifier : 1, neighbors: [ "Alice", "Cathy" ] } // { identifier : 2, neighbors: [] } // { identifier : 3, neighbors: "Bob" } const results = await db.pipeline() .database() .unnest(Field.of("neighbors"), "unnestedNeighbors", "index") .execute(); // Output // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Alice", index: 0 } // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Cathy", index: 1 } // { identifier: 3, neighbors: "Bob", index: null}
Swift
// Input // { identifier : 1, neighbors: [ "Alice", "Cathy" ] } // { identifier : 2, neighbors: [] } // { identifier : 3, neighbors: "Bob" } let results = try await db.pipeline() .database() .unnest(Field("neighbors").as("unnestedNeighbors"), indexField: "index") .execute() // Output // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Alice", index: 0 } // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Cathy", index: 1 } // { identifier: 3, neighbors: "Bob", index: null}
Kotlin
// Input // { identifier : 1, neighbors: [ "Alice", "Cathy" ] } // { identifier : 2, neighbors: [] } // { identifier : 3, neighbors: "Bob" } val results = db.pipeline() .database() .unnest(field("neighbors").alias("unnestedNeighbors"), UnnestOptions().withIndexField("index")) .execute() // Output // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Alice", index: 0 } // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Cathy", index: 1 } // { identifier: 3, neighbors: "Bob", index: null}
Java
// Input // { identifier : 1, neighbors: [ "Alice", "Cathy" ] } // { identifier : 2, neighbors: [] } // { identifier : 3, neighbors: "Bob" } Task<Pipeline.Snapshot> results = db.pipeline() .database() .unnest(field("neighbors").alias("unnestedNeighbors"), new UnnestOptions().withIndexField("index")) .execute(); // Output // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Alice", index: 0 } // { identifier: 1, neighbors: [ "Alice", "Cathy" ], unnestedNeighbors: "Cathy", index: 1 } // { identifier: 3, neighbors: "Bob", index: null}
Python
from google.cloud.firestore_v1.pipeline_expressions import Field from google.cloud.firestore_v1.pipeline_stages import UnnestOptions # Input # { "identifier" : 1, "neighbors": [ "Alice", "Cathy" ] } # { "identifier" : 2, "neighbors": [] } # { "identifier" : 3, "neighbors": "Bob" } results = ( client.pipeline() .database() .unnest( Field.of("neighbors").as_("unnestedNeighbors"), options=UnnestOptions(index_field="index"), ) .execute() ) # Output # { "identifier": 1, "neighbors": [ "Alice", "Cathy" ], # "unnestedNeighbors": "Alice", "index": 0 } # { "identifier": 1, "neighbors": [ "Alice", "Cathy" ], # "unnestedNeighbors": "Cathy", "index": 1 } # { "identifier": 3, "neighbors": "Bob", "index": null}
Java
// Input // { "identifier" : 1, "neighbors": [ "Alice", "Cathy" ] } // { "identifier" : 2, "neighbors": [] } // { "identifier" : 3, "neighbors": "Bob" } Pipeline.Snapshot results = firestore .pipeline() .database() .unnest("neighbors", "unnestedNeighbors", new UnnestOptions().withIndexField("index")) .execute() .get(); // Output // { "identifier": 1, "neighbors": [ "Alice", "Cathy" ], // "unnestedNeighbors": "Alice", "index": 0 } // { "identifier": 1, "neighbors": [ "Alice", "Cathy" ], // "unnestedNeighbors": "Cathy", "index": 1 } // { "identifier": 3, "neighbors": "Bob", "index": null}
Go
// Input // { "identifier" : 1, "neighbors": [ "Alice", "Cathy" ] } // { "identifier" : 2, "neighbors": [] } // { "identifier" : 3, "neighbors": "Bob" } results, err := client.Pipeline(). Database(). UnnestWithAlias("neighbors", "unnestedNeighbors", firestore.WithUnnestIndexField("index")). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Output // { "identifier": 1, "neighbors": [ "Alice", "Cathy" ], // "unnestedNeighbors": "Alice", "index": 0 } // { "identifier": 1, "neighbors": [ "Alice", "Cathy" ], // "unnestedNeighbors": "Cathy", "index": 1 } // { "identifier": 3, "neighbors": "Bob", "index": nil}
İç içe yerleştirme ve iç içe yerleştirmeyi kaldırma
İfade iç içe geçmiş bir dizi olarak değerlendirildiğinde, her iç içe geçmiş düzeyi düzleştirmek için birden fazla unnest(...) aşama kullanılmalıdır.
Örneğin, aşağıdaki koleksiyon için:
Node.js
await db.collection("users").add({name: "foo", record: [{scores: [5, 4], avg: 4.5}, {scores: [1, 3], old_avg: 2}]});
En içteki diziyi ayıklamak için unnest(...) aşaması sırayla kullanılabilir.
Node.js
const userScore = await db.pipeline()
.collection("/users")
.unnest(field("record").as("record"))
.unnest(field("record.scores").as("userScore"), /* index_field= */ "attempt")
.execute();
Bu işlem sonucunda aşağıdaki belgeler oluşturulur:
{ name: "foo", record: [{ scores: [5, 4], avg: 4.5 }], userScore: 5, attempt: 0 }
{ name: "foo", record: [{ scores: [5, 4], avg: 4.5 }], userScore: 4, attempt: 1 }
{ name: "foo", record: [{ scores: [1, 3], avg: 2 }], userScore: 1, attempt: 0 }
{ name: "foo", record: [{ scores: [1, 3], avg: 2 }], userScore: 3, attempt: 1 }