Definição
$fill
Novidades na versão 5.3.
Preenche
null
e os valores de campo ausentes nos documentos.Você pode utilizar o
$fill
para preencher pontos de dados ausentes:Em uma sequência baseada em valores circundantes.
Com um valor fixo.
Sintaxe
O estágio $fill
tem esta sintaxe:
{ $fill: { partitionBy: <expression>, partitionByFields: [ <field 1>, <field 2>, ... , <field n> ], sortBy: { <sort field 1>: <sort order>, <sort field 2>: <sort order>, ..., <sort field n>: <sort order> }, output: { <field 1>: { value: <expression> }, <field 2>: { method: <string> }, ... } } }
O estágio $fill
toma um documento com estes campos:
Campo | necessidade | Descrição |
---|---|---|
Opcional | Especifica uma expressão para agrupar os documentos. Na etapa, um grupo de Se você omitir partitionBy e partitionByFields, o usará uma partição para toda a partitionBy e partitionByFields são mutuamente exclusivos. Veja um exemplo. | |
Opcional | Especifica uma array de campos como a chave composta para agrupar os documentos. No estágio, cada grupo de Se você omitir partitionBy e partitionByFields, o usará uma partição para toda a partitionBy e partitionByFields são mutuamente exclusivos. | |
Necessário se o método for especificado em pelo menos uma <field>saída.. Caso contrário, opcional. | Especifica o campo ou campos para classificar os documentos dentro de cada partição. Utiliza a mesma sintaxe que o estágio | |
Obrigatório | ||
Obrigatório | Especifica um objeto indicando como preencher valores ausentes no campo de destino. O nome do objeto deve ser
|
Comportamento e restrições
partitionByFields
Restrições
$fill
retorna um erro se houver algum nome de campo na array partitionByFields:
Avalia para um valor não string.
Começa com
$
.
linear
Comportamento
O método de preenchimento linear
preenche campos null
e ausentes usando interpolação linear com base nos valores não-null
circundantes na sequência.
Para cada documento em que o campo é
null
ou ausente,linearFill
preenche esses campos na proporção do intervalo de valores ausentes entre os valores não circundantes,null
de acordo com a ordem SortBy . Para determinar os valores para campos ausentes, olinearFill
utiliza:A diferença entre os valores circundantes que não são
null
.O número de
null
campos para preencher entre os valores circundantes.
O método
linear
pode preencher vários valores denull
consecutivos se esses valores forem precedidos e seguidos por valores nãonull
de acordo com a ordem sortBy .Exemplo
Se uma coleção contiver estes documentos:
{ index: 0, value: 0 }, { index: 1, value: null }, { index: 2, value: null }, { index: 3, value: null }, { index: 4, value: 10 } Após utilizar o método de preenchimento
linear
para preencher os valoresnull
, os documentos tornam-se:{ index: 0, value: 0 }, { index: 1, value: 2.5 }, { index: 2, value: 5 }, { index: 3, value: 7.5 }, { index: 4, value: 10 } null
valores que não são precedidos e seguidos por valores diferentes denull
permanecemnull
.Para usar o método de preenchimento
linear
, você também deve usar o campo sortBy para classificar os dados.
Para um exemplo completo utilizando o método de preenchimento linear
, consulte Preencher valores de campo ausentes com interpolação linear.
locf
Comportamento
locf
significa a última observação realizada.
Se um campo que está sendo preenchido contiver valores
null
e não nulos,locf
definirá os valoresnull
e ausentes como o último valor não nulo conhecido do campo, de acordo com a ordem sortBy.Se o campo contiver apenas
null
ou valores ausentes em uma partição,locf
definirá o valor do campo comonull
para essa partição.null
e os valores de campo ausentes que aparecem antes dos valores não nulos na ordem de classificação permanecemnull
.
Para usar o método de preenchimento
locf
, você também deve usar o campo sortBy para classificar os dados.
Para um exemplo completo utilizando o método de preenchimento locf
, consulte Preencher Valores de Campo Faltando Baseado no Último Valor Observado.
Comparação de $fill
e Operadores de Agregação
Para preencher null
e os valores de campo ausentes em um documento, você pode usar:
O estágio
$fill
.Quando você utiliza o estágio
$fill
, o campo que você especifica na saída é o mesmo campo utilizado como os dados de origem.Os operadores de agregação
$linearFill
e$locf
.Quando você
$linearFill
ou$locf
, você pode configurar valores para um campo diferente do campo utilizado como os dados de origem.
Exemplos
Os exemplos nesta seção mostram como utilizar o $fill
para preencher valores ausentes:
Preencher valores de campo ausentes com um valor constante
Uma loja de calçados mantém uma coleção dailySales
que contém um documento resumindo as vendas de cada dia. A loja de sapatos vende estes tipos de sapatos:
boots
sandals
sneakers
Crie a seguinte coleção do dailySales
:
db.dailySales.insertMany( [ { "date": ISODate("2022-02-02"), "bootsSold": 10, "sandalsSold": 20, "sneakersSold": 12 }, { "date": ISODate("2022-02-03"), "bootsSold": 7, "sneakersSold": 18 }, { "date": ISODate("2022-02-04"), "sneakersSold": 5 } ] )
Nem todos os documentos na coleção dailySales
contêm cada tipo de sapato. Se um tipo de sapato estiver faltando, significa que não havia sapatos desse tipo vendidos na data correspondente.
O exemplo a seguir usa $fill
para definir as quantidades vendidas para 0
para os tipos de sapatos ausentes para as vendas de cada dia:
db.dailySales.aggregate( [ { $fill: { output: { "bootsSold": { value: 0 }, "sandalsSold": { value: 0 }, "sneakersSold": { value: 0 } } } } ] )
No pipeline anterior:
$fill
preenche valores para campos em falta.saída especifica:
Os nomes dos campos para preencher.
- O valor para definir os campos preenchidos. Neste exemplo, o
- saída especifica um valor constante de
0
.
Saída de exemplo:
[ { _id: ObjectId("6202df9f394d47411658b51e"), date: ISODate("2022-02-02T00:00:00.000Z"), bootsSold: 10, sandalsSold: 20, sneakersSold: 12 }, { _id: ObjectId("6202df9f394d47411658b51f"), date: ISODate("2022-02-03T00:00:00.000Z"), bootsSold: 7, sneakersSold: 18, sandalsSold: 0 }, { _id: ObjectId("6202df9f394d47411658b520"), date: ISODate("2022-02-04T00:00:00.000Z"), sneakersSold: 5, bootsSold: 0, sandalsSold: 0 } ]
Preencher valores de campo ausentes com interpolação linear
Crie uma coleção stock
que contenha os seguintes documentos, que acompanham o preço das ações de uma única empresa em intervalos de hora em hora:
db.stock.insertMany( [ { time: ISODate("2021-03-08T09:00:00.000Z"), price: 500 }, { time: ISODate("2021-03-08T10:00:00.000Z"), }, { time: ISODate("2021-03-08T11:00:00.000Z"), price: 515 }, { time: ISODate("2021-03-08T12:00:00.000Z") }, { time: ISODate("2021-03-08T13:00:00.000Z") }, { time: ISODate("2021-03-08T14:00:00.000Z"), price: 485 } ] )
O campo price
está faltando em alguns documentos da coleção.
Para preencher os price
valores de ausentes utilizando interpolação linear, utilize com $fill
o linear
método de preenchimento:
db.stock.aggregate( [ { $fill: { sortBy: { time: 1 }, output: { "price": { method: "linear" } } } } ] )
No pipeline anterior:
$fill
preenche valores para campos em falta.sortBy: { time: 1 }
classifica os documentos pelo campotime
em ordem crescente, do mais antigo ao mais recente.saída especifica:
price
como o campo para o qual preencher os valores ausentes.{ method: "linear" }
como método de preenchimento. O preenchimentolinear
- O método preenche
price
os valores ausentes usando interpolação linear com base nosprice
valores adjacentes na sequência.
Saída de exemplo:
[ { _id: ObjectId("620ad41c394d47411658b5e9"), time: ISODate("2021-03-08T09:00:00.000Z"), price: 500 }, { _id: ObjectId("620ad41c394d47411658b5ea"), time: ISODate("2021-03-08T10:00:00.000Z"), price: 507.5 }, { _id: ObjectId("620ad41c394d47411658b5eb"), time: ISODate("2021-03-08T11:00:00.000Z"), price: 515 }, { _id: ObjectId("620ad41c394d47411658b5ec"), time: ISODate("2021-03-08T12:00:00.000Z"), price: 505 }, { _id: ObjectId("620ad41c394d47411658b5ed"), time: ISODate("2021-03-08T13:00:00.000Z"), price: 495 }, { _id: ObjectId("620ad41c394d47411658b5ee"), time: ISODate("2021-03-08T14:00:00.000Z"), price: 485 } ]
Preencher valores de campo ausentes com base no último valor observado
Crie uma coleção restaurantReviews
que contenha os seguintes documentos, que armazenam as pontuações das avaliações de um único restaurante ao longo do tempo:
db.restaurantReviews.insertMany( [ { date: ISODate("2021-03-08"), score: 90 }, { date: ISODate("2021-03-09"), score: 92 }, { date: ISODate("2021-03-10") }, { date: ISODate("2021-03-11") }, { date: ISODate("2021-03-12"), score: 85 }, { date: ISODate("2021-03-13") } ] )
O campo score
está faltando em alguns documentos da coleção.
Para preencher os campos de score
ausentes e garantir que não haja lacunas nos dados, use $fill
. No exemplo seguinte, $fill
usa o método locf
para preencher os valores de score
ausentes com a score
anterior na sequência:
db.restaurantReviews.aggregate( [ { $fill: { sortBy: { date: 1 }, output: { "score": { method: "locf" } } } } ] )
No pipeline anterior:
$fill
preenche os valores ausentes descore
.sortBy: { date: 1 }
classifica os documentos pelo campodate
em ordem crescente, do mais antigo ao mais recente.saída especifica:
score
como o campo para o qual preencher os valores ausentes.{ method: "locf" }
como método de preenchimento. O preenchimentolocf
- O método preenche os valores
score
ausentes com o últimoscore
observado na sequência.
Saída de exemplo:
[ { _id: ObjectId("62040bc9394d47411658b553"), date: ISODate("2021-03-08T00:00:00.000Z"), score: 90 }, { _id: ObjectId("62040bc9394d47411658b554"), date: ISODate("2021-03-09T00:00:00.000Z"), score: 92 }, { _id: ObjectId("62040bc9394d47411658b555"), date: ISODate("2021-03-10T00:00:00.000Z"), score: 92 }, { _id: ObjectId("62040bc9394d47411658b556"), date: ISODate("2021-03-11T00:00:00.000Z"), score: 92 }, { _id: ObjectId("62040bc9394d47411658b557"), date: ISODate("2021-03-12T00:00:00.000Z"), score: 85 }, { _id: ObjectId("62040bc9394d47411658b558"), date: ISODate("2021-03-13T00:00:00.000Z"), score: 85 } ]
Preencha dados para partições distintas
Considere o exemplo anterior com avaliações de restaurantes, mas em vez de rastrear um único restaurante, a coleção agora contém avaliações de vários restaurantes.
Crie uma coleção denominada restaurantReviewsMultiple
e preencha a coleção com estes documentos:
db.restaurantReviewsMultiple.insertMany( [ { date: ISODate("2021-03-08"), restaurant: "Joe's Pizza", score: 90 }, { date: ISODate("2021-03-08"), restaurant: "Sally's Deli", score: 75 }, { date: ISODate("2021-03-09"), restaurant: "Joe's Pizza", score: 92 }, { date: ISODate("2021-03-09"), restaurant: "Sally's Deli" }, { date: ISODate("2021-03-10"), restaurant: "Joe's Pizza" }, { date: ISODate("2021-03-10"), restaurant: "Sally's Deli", score: 68 }, { date: ISODate("2021-03-11"), restaurant: "Joe's Pizza", score: 93 }, { date: ISODate("2021-03-11"), restaurant: "Sally's Deli" } ] )
O campo score
está faltando em alguns documentos da coleção.
Para preencher os campos de score
ausentes e garantir que não haja lacunas nos dados, use $fill
. No exemplo seguinte, $fill
usa o método locf
para preencher os valores de score
ausentes com a score
anterior na sequência:
db.restaurantReviewsMultiple.aggregate( [ { $fill: { sortBy: { date: 1 }, partitionBy: { "restaurant": "$restaurant" }, output: { "score": { method: "locf" } } } } ] )
No pipeline anterior:
$fill
preenche os valores ausentes descore
.sortBy: { date: 1 }
classifica os documentos pelo campodate
em ordem crescente, do mais antigo ao mais recente.partitionBy: { "restaurant": "$restaurant" }
partições dos dados derestaurant
. Existem dois restaurantes:Joe's Pizza
eSally's Deli
.saída especifica:
score
como o campo para o qual preencher os valores ausentes.{ method: "locf" }
como método de preenchimento. O preenchimentolocf
- O método preenche os valores
score
ausentes com o últimoscore
observado na sequência.
Saída de exemplo:
[ { _id: ObjectId("620559f4394d47411658b58f"), date: ISODate("2021-03-08T00:00:00.000Z"), restaurant: "Joe's Pizza", score: 90 }, { _id: ObjectId("620559f4394d47411658b591"), date: ISODate("2021-03-09T00:00:00.000Z"), restaurant: "Joe's Pizza", score: 92 }, { _id: ObjectId("620559f4394d47411658b593"), date: ISODate("2021-03-10T00:00:00.000Z"), restaurant: "Joe's Pizza", score: 92 }, { _id: ObjectId("620559f4394d47411658b595"), date: ISODate("2021-03-11T00:00:00.000Z"), restaurant: "Joe's Pizza", score: 93 }, { _id: ObjectId("620559f4394d47411658b590"), date: ISODate("2021-03-08T00:00:00.000Z"), restaurant: "Sally's Deli", score: 75 }, { _id: ObjectId("620559f4394d47411658b592"), date: ISODate("2021-03-09T00:00:00.000Z"), restaurant: "Sally's Deli", score: 75 }, { _id: ObjectId("620559f4394d47411658b594"), date: ISODate("2021-03-10T00:00:00.000Z"), restaurant: "Sally's Deli", score: 68 }, { _id: ObjectId("620559f4394d47411658b596"), date: ISODate("2021-03-11T00:00:00.000Z"), restaurant: "Sally's Deli", score: 68 } ]
Indique se um campo foi preenchido usando $fill
Quando você preenche valores ausentes, a saída não indica se um valor foi preenchido com o operador $fill
ou se o valor existia no documento originalmente. Para distinguir entre valores preenchidos e preexistentes, você pode usar um estágio $set
antes de $fill
e definir um novo campo com base na existência ou não do valor.
Por exemplo, crie uma coleção restaurantReviews
que contenha os seguintes documentos, que armazenam as pontuações das avaliações de um restaurante ao longo do tempo:
db.restaurantReviews.insertMany( [ { date: ISODate("2021-03-08"), score: 90 }, { date: ISODate("2021-03-09"), score: 92 }, { date: ISODate("2021-03-10") }, { date: ISODate("2021-03-11") }, { date: ISODate("2021-03-12"), score: 85 }, { date: ISODate("2021-03-13") } ] )
O campo score
está faltando em alguns documentos da coleção. Você pode preencher os valores score
ausentes usando o operador $fill
.
Crie um pipeline para executar as seguintes ações:
Use para adicionar um novo campo a cada documento , indicando se o campo do
$set
documentoscore
existe antes do$fill
operador preencher os valores. Este novo campo évalueExisted
chamado.Preencha os valores
score
ausentes com o últimoscore
observado na sequência. O método de preenchimentolocf
significa "última observação realizada adiante".
O pipeline se assemelha ao seguinte código:
db.restaurantReviews.aggregate( [ { $set: { "valueExisted": { "$ifNull": [ { "$toBool": { "$toString": "$score" } }, false ] } } }, { $fill: { sortBy: { date: 1 }, output: { "score": { method: "locf" } } } } ] )
Observação
Manipulação de valores de zero
Saída:
[ { _id: ObjectId("63595116b1fac2ee2e957f15"), date: ISODate("2021-03-08T00:00:00.000Z"), score: 90, valueExisted: true }, { _id: ObjectId("63595116b1fac2ee2e957f16"), date: ISODate("2021-03-09T00:00:00.000Z"), score: 92, valueExisted: true }, { _id: ObjectId("63595116b1fac2ee2e957f17"), date: ISODate("2021-03-10T00:00:00.000Z"), valueExisted: false, score: 92 }, { _id: ObjectId("63595116b1fac2ee2e957f18"), date: ISODate("2021-03-11T00:00:00.000Z"), valueExisted: false, score: 92 }, { _id: ObjectId("63595116b1fac2ee2e957f19"), date: ISODate("2021-03-12T00:00:00.000Z"), score: 85, valueExisted: true }, { _id: ObjectId("63595116b1fac2ee2e957f1a"), date: ISODate("2021-03-13T00:00:00.000Z"), valueExisted: false, score: 85 } ]
Os exemplos do Node.js nesta página usam a sample_weatherdata.data
collection dos conjuntos de dados de amostra do Atlas . Para saber como criar um cluster gratuito do MongoDB Atlas e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver do MongoDB Node.js
Para usar o driver Node.js do MongoDB para adicionar um estágio $fill
a um pipeline de agregação , use o operador $fill
em um objeto de pipeline.
O exemplo a seguir cria um pipeline que preenche valores nulos ou ausentes. O pipeline inclui os seguintes estágios:
O estágio agrupa documentos de entrada por
$group
seuts
campo e calcula a médiaseaSurfaceTemperature.value
de cada grupo.O estágio classifica os dados agrupados
$fill
pelo_id
campo em ordem crescente e preenche valores nulos ouseaSurfaceTemperature
ausentes usando interpolação linear.
const pipeline = [ { $group: { _id: "$ts", seaSurfaceTemperature: { $avg: "$seaSurfaceTemperature.value" }, } }, { $fill: { sortBy: { _id: 1 }, output: { seaSurfaceTemperature: { method: "linear" } } } } ]; const cursor = collection.aggregate(pipeline); return cursor;