Menu Docs

Página inicial do DocsDesenvolver aplicaçõesManual do MongoDB

$dateSubtract (agregação)

Nesta página

  • Definição
  • Comportamento
  • Exemplos
$dateSubtract

Novidades na versão 5,0.

Reduz um objeto Date() por um número específico de unidades de tempo.

A expressão $dateSubtract tem a seguinte sintaxe:

{
$dateSubtract: {
startDate: <Expression>,
unit: <Expression>,
amount: <Expression>,
timezone: <tzExpression>
}
}

Retorna um Date(). O startDate pode ser qualquer expressão que resolva o tipo Date, Timestamp ou ObjectId. Não importa qual tipo de dados é usado como entrada, o valor retornado será um objeto Date() .

Campo
Obrigatório/Opcional
Descrição
startDate
Obrigatório
A data de início, em UTC, para a operação de subtração. O startDate pode ser qualquer expressão que resolva para uma Data, um Timestamp ou um ObjectID.
unit
Obrigatório

O unit usado para medir o amount de tempo subtraído do startDate. O unit é uma expressão que se resolve em uma das seguintes strings:

  • year

  • quarter

  • week

  • month

  • day

  • hour

  • minute

  • second

  • millisecond

amount
Obrigatório
O número de units subtraído de startDate. O amount é uma expressão que resolve para um inteiro ou longo. O amount também pode resolver para um decimal integral e ou um dobro se esse valor puder ser convertido em um longo sem perda de precisão.
timezone
Opcional

O fuso horário para realizar a operação. <tzExpression> deve ser uma expressão válida que resolva para uma string formatada como um identificador de fuso horário Olson ou um UTC Offset. Se nenhum timezone for fornecido, o resultado será exibido em UTC.

Formatar
Exemplos
Identificador de fuso horário Olson
"America/New_York"
"Europe/London"
"GMT"
UTC Offset
+/-[hh]:[mm], e.g. "+04:45"
+/-[hh][mm], e.g. "-0530"
+/-[hh], e.g. "+03"

Para mais informações sobre expressões e tipos, consulte Operadores de Expressão e Tipos de JSON.

O MongoDB segue o uso predominante do banco de dados e trabalha com o tempo em UTC. A expressão dateSubtract sempre pega um startDate em UTC e retorna um resultado em UTC. Se o timezone for especificado, o cálculo será feito utilizando o timezone especificado. O fuso horário é especialmente importante quando um cálculo envolve Horário de Verão (DST).

Se unit for month ou maior, a operação será ajustada para contabilizar o último dia do mês. Subtraindo um month no último dia de março, por exemplo, demonstra o ajuste de "último dia do mês".

{
$dateSubtract:
{
startDate: ISODate("2021-03-31T12:10:05Z"),
unit: "month",
amount: 1
}
}

Observe que a data de regresso, ISODate("2021-02-28T12:10:05Z"), é a e não a desde fevereiro tem menos dias do que março.

Ao usar um Identificador de Fuso Horário Olson no campo <timezone>, o MongoDB aplica o deslocamento de horáriode verão , se aplicável, para o fuso horário especificado.

Por exemplo, considere uma collection sales com o seguinte documento:

{
"_id" : 1,
"item" : "abc",
"price" : 20,
"quantity" : 5,
"date" : ISODate("2017-05-20T10:24:51.303Z")
}

A seguinte agregação ilustra como o MongoDB lida com o deslocamento DST para o Identificador de fuso horário Olson. O exemplo utiliza os operadores $hour e $minute para retornar as partes correspondentes do campo date:

db.sales.aggregate([
{
$project: {
"nycHour": {
$hour: { date: "$date", timezone: "-05:00" }
},
"nycMinute": {
$minute: { date: "$date", timezone: "-05:00" }
},
"gmtHour": {
$hour: { date: "$date", timezone: "GMT" }
},
"gmtMinute": {
$minute: { date: "$date", timezone: "GMT" } },
"nycOlsonHour": {
$hour: { date: "$date", timezone: "America/New_York" }
},
"nycOlsonMinute": {
$minute: { date: "$date", timezone: "America/New_York" }
}
}
}])

A operação retorna o seguinte resultado:

{
"_id": 1,
"nycHour" : 5,
"nycMinute" : 24,
"gmtHour" : 10,
"gmtMinute" : 24,
"nycOlsonHour" : 6,
"nycOlsonMinute" : 24
}

Considere uma coleção de tempos de conexão do sistema como estes:

db.connectionTime.insertMany(
[
{
custId: 457,
login: ISODate("2020-12-25T19:04:00"),
logout: ISODate("2020-12-28T09:04:00")
},
{
custId: 457,
login: ISODate("2021-01-27T05:12:00"),
logout: ISODate("2021-01-28T13:05:00")
},
{
custId: 458,
login: ISODate("2021-01-22T06:27:00"),
logout: ISODate("2021-01-31T11:00:00")
},
{
custId: 459,
login: ISODate("2021-02-14T20:14:00"),
logout: ISODate("2021-02-17T16:05:00")
},
{
custId: 460,
login: ISODate("2021-02-26T02:44:00"),
logout: ISODate("2021-02-18T14:13:00")
}
]
)

Devido a um problema de serviço, você precisa subtrair 3 horas de cada um dos horários de logout de janeiro de 2021. Você pode usar $dateSubtract em um aggregation pipeline para diminuir o logoutTime.

db.connectionTime.aggregate(
[
{
$match:
{
$expr:
{
$eq:
[
{ $year: "$logout" },
2021
]
},
$expr:
{
$eq:
[
{ $month: "$logout" },
1
]
}
}
},
{
$project:
{
logoutTime:
{
$dateSubtract:
{
startDate: "$logout",
unit: "hour",
amount: 3
}
}
}
},
{
$merge: "connectionTime"
}
]
)

Duas comparações semelhantes são feitas no estágio $match. Primeiro, os operadores $year e $month extraem o ano e o mês, respectivamente, do objeto Data logoutTime. Em seguida, o mês e o ano são verificados para ver se correspondem às metas de seleção. Como "janeiro" é codificado como "1", $expr é verdadeiro quando o ano e o mês são iguais ($eq) a "2021" e "1".

O estágio $project utiliza $dateSubtract para subtrair 3 horas do logoutTime de cada dcoumento selecionado.

O estágio $merge atualiza a coleção, escrevendo o novo logoutTime para os documentos modificados.

Observação

Ao contrário $out, o estágio $merge apenas atualiza os documentos correspondentes e preserva o restante da coleção. Para mais detalhes, consulte: $out em comparação com $merge.

Os documentos resultantes têm a seguinte aparência:

{
"_id" : ObjectId("603dd94b044b995ad331c0b5"),
"custId" : 457,
"login" : ISODate("2020-12-25T19:04:00Z"),
"logout" : ISODate("2020-12-28T09:04:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b6"),
"custId" : 457,
"login" : ISODate("2021-01-27T05:12:00Z"),
"logout" : ISODate("2021-01-28T13:05:00Z"),
"logoutTime" : ISODate("2021-01-28T10:05:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b7"),
"custId" : 458,
"login" : ISODate("2021-01-22T06:27:00Z"),
"logout" : ISODate("2021-01-31T11:00:00Z"),
"logoutTime" : ISODate("2021-01-31T08:00:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b8"),
"custId" : 459,
"login" : ISODate("2021-02-14T20:14:00Z"),
"logout" : ISODate("2021-02-17T16:05:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b9"),
"custId" : 460,
"login" : ISODate("2021-02-26T02:44:00Z"),
"logout" : ISODate("2021-02-18T14:13:00Z")
}

Você deseja enviar uma pesquisa para clientes que usaram seu serviço na última semana. A expressão $dateSubtract pode criar um filtro de intervalo relativo ao tempo em que a consulta é executada.

db.connectionTime.aggregate(
[
{
$match:
{
$expr:
{
$gt:
[
"$logoutTime",
{
$dateSubtract:
{
startDate: "$$NOW",
unit: "week",
amount: 1
}
}
]
}
}
},
{
$project:
{
_id: 0,
custId: 1,
loggedOut:
{
$dateToString:
{
format: "%Y-%m-%d",
date: "$logoutTime"
}
}
}
}
]
)

A variável de agregação incorporada $$NOW retorna a data/hora atual no formato ISODate. O estágio $match usa o valor em $$NOW para obter a data de hoje. Em seguida, a expressão de comparação ($expr) filtra a coleção usando maior que ($gt) e $dateSubtract para combinar documentos que tiveram logoutTime na semana passada.

O estágio $project utiliza a expressão $dateToString para converter as datas em um formato mais legível. Sem a conversão, o MongoDB retornaria a data no formato ISODate. O resultado mostra que dois clientes se desconectaram na última semana.

{ "custId" : 459, "loggedOut" : "2021-02-17" }
{ "custId" : 460, "loggedOut" : "2021-02-18" }

Todas as datas são armazenadas internamente no horário UTC. Quando um timezone é especificado, o $dateSubtract utiliza a hora local para executar os cálculos. Os resultados são exibidos em UTC.

Você tem clientes em vários fusos horários e deseja ver o efeito que o horário de verão pode ter em seus períodos de faturamento se você faturar por day ou por hour.

Criar esta coleção de tempos de conexão:

db.billing.insertMany(
[
{
location: "America/New_York",
login: ISODate("2021-03-14T10:00:00-0500"),
logout: ISODate("2021-03-14T18:00:00-0500")
},
{
location: "America/Mexico_City",
login: ISODate("2021-03-14T10:00:00-00:00"),
logout: ISODate("2021-03-15T08:00:00-0500")
}
]
)

Primeiro subtraia 1 dia e, em seguida, subtraia 24 horas das login datas em cada documento.

db.billing.aggregate(
[
{
$project:
{
_id: 0,
location: 1,
start:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date: "$login"
}
},
days:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "day",
amount: 1,
timezone: "$location"
}
}
}
},
hours:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "hour",
amount: 24,
timezone: "$location"
}
}
}
},
startTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date: "$login",
timezone: "$location"
}
},
daysTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "day",
amount: 1,
timezone: "$location"
}
},
timezone: "$location"
}
},
hoursTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "hour",
amount: 24,
timezone: "$location"
}
},
timezone: "$location"
}
},
}
}
]
).pretty()

A expressão $dateToString reformata a saída para legibilidade. Os resultados são resumidos aqui:

Campo
Nova York
Cidade do México
Iniciar
2021-03-14 15:00
2021-03-14 15:00
Início, TZ Info
2021-03-14 11:00
2021-03-14 04:00
1 dia
2021-03-13 16:00
2021-03-13 15:00
1 dias, TZInfo
2021-03-13 11:00
2021-03-13 09:00
24 horas
2021-03-13 15:00
2021-03-13 15:00
24 horas, TZInfo
2021-03-13 10:00
2021-03-13 09:00

O gráfico destaca vários pontos:

  • As datas não formatadas retornam em UTC. O $login para Nova York é UTC -5, no entanto, as linhas start, days e hours exibem o tempo em UTC.

  • de março é o início do DST em Nova York, mas não no México. O tempo calculado é ajustado quando um local muda para DST e cruza de um day para o outro.

  • O horário de verão modifica o comprimento do day, não do hour. Não há alteração de DST para hours. Só há um ajuste para o horário de verão quando a medida unit é day ou maior e o cálculo ultrapassa uma mudança de relógio no timezone especificado.

Dica

Veja também:

← $dateFromString (agregação)