Há algumas maneiras de fazer isso.
A primeira é com os operadores de agregação de datas, que permitem dissecar os valores de "data" em documentos. Especificamente para "agrupar" como a intenção principal:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$created_at" },
"dayOfYear": { "$dayOfYear": "$created_at" },
"hour": { "$hour": "$created_at" },
"interval": {
"$subtract": [
{ "$minute": "$created_at" },
{ "$mod": [{ "$minute": "$created_at"}, 15] }
]
}
}},
"count": { "$sum": 1 }
}}
])
A segunda maneira é usar um pequeno truque de quando um objeto de data é subtraído (ou outra operação matemática direta) de outro objeto de data, então o resultado é um valor numérico que representa os milissegundos do timestamp da época entre os dois objetos. Então, apenas usando a data de época, você obtém a representação de milissegundos de época. Em seguida, use a matemática da data para o intervalo:
db.collection.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
{ "$mod": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
1000 * 60 * 15
]}
]
},
"count": { "$sum": 1 }
}}
])
Portanto, depende de que tipo de formato de saída você deseja para o intervalo de agrupamento. Ambos representam basicamente a mesma coisa e possuem dados suficientes para serem reconstruídos como um objeto "data" em seu código.
Você pode colocar o que quiser na parte "operador de agrupamento" após o agrupamento
_id
. Estou apenas usando o exemplo básico de "contagem" em vez de qualquer declaração real de você mesmo sobre o que você realmente quer fazer. MongoDB 4.xe superior
Houve algumas adições aos operadores de agregação de datas desde a escrita original, mas a partir do MongoDB 4.0 haverá uma "conversão real de tipos" em oposição aos truques matemáticos básicos feitos aqui com a conversão de data BSON.
Por exemplo, podemos usar
$toLong
e $toDate
como novos ajudantes aqui:db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": "$created_at" },
{ "$mod": [ { "$toLong": "$created_at" }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Isso é um pouco mais curto e não requer a definição de uma data BSON externa para o valor "epoch" como uma constante na definição do pipeline, por isso é bastante consistente para todas as implementações de linguagem.
Esses são apenas dois dos métodos "auxiliares" para conversão de tipo, todos vinculados ao
$convert
método, que é uma forma "mais longa" da implementação que permite manipulação personalizada em null
ou erro na conversão. É até possível com essa transmissão obter a
Date
informações do ObjectId
da chave primária, pois esta seria uma fonte confiável de data de "criação":db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": { "$toDate": "$_id" } },
{ "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Portanto, "tipos de elenco" com esse tipo de conversão podem ser uma ferramenta bastante poderosa.
Aviso -ObjectId
os valores são limitados à precisão ao segundo apenas para o valor de tempo interno que compõe parte de seus dados, permitindo que o$toDate
conversão. O "tempo" real inserido provavelmente depende do driver em uso. Onde precisão for obrigatório, ainda é recomendável usar um campo BSON Date discreto em vez de confiar emObjectId
valores.