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 valores de price
ausentes utilizando interpolação linear, utilize $fill
com o método de preenchimento linear
:
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 os valores
price
ausentes usando interpolação linear com base nos valoresprice
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
$set
para adicionar um novo campo a cada documento, indicando se o camposcore
do documento existe antes do operador$fill
preencher os valores. Este novo campo é chamadovalueExisted
.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 } ]
Interpolar valores idênticos em diferentes partições
Alterado na versão 8.1.
A partir do MongoDB 8.1, $fill
pode usar o método linear
para interpolar se houver valores idênticos em partições diferentes.
Crie a seguinte coleção restaurantReviewsMultiple
que contenha os seguintes documentos, que armazenam as pontuações das avaliações de restaurantes em datas idênticas:
db.restaurantReviewsMultiple.insertMany( [ { date: ISODate("2021-03-08"), restaurant: "Steve's Pizza", score: 90 }, { date: ISODate("2021-03-08"), restaurant: "Sally's Deli", score: 75 } ] )
O seguinte exemplo de agregação utiliza "linear"
para interpolar as datas idênticas nas diferentes partições:
db.restaurantReviewsMultiple.aggregate( [ { $fill: { sortBy: { date: 1 }, partitionBy: { "restaurant": "$restaurant" }, output: { "score": { method: "linear" } } } } ] )
Iniciando no MongoDB 8.1, o exemplo retorna a seguinte saída:
[ { _id: ObjectId("620559f4394d47411658b590"), date: ISODate("2021-03-08T00:00:00.000Z"), restaurant: "Sally's Deli", score: 75 }, { _id: ObjectId("620559f4394d47411658b58f"), date: ISODate("2021-03-08T00:00:00.000Z"), restaurant: "Steve's Pizza", score: 90 } ]
Os exemplos de Node.js nesta página usam a coleção sample_weatherdata.data
dos conjuntos de dados de amostra do Atlas. Para aprender como criar um cluster gratuito do MongoDB Atlas e carregar os conjuntos de dados de amostra, consulte Introdução na documentação do driver 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
$group
agrupa documentos de entrada por seu campots
e calcula a média de cada gruposeaSurfaceTemperature.value
.O estágio
$fill
classifica os dados agrupados pelo campo_id
em ordem crescente e preenche valoresseaSurfaceTemperature
nulos ou 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;