Hai scritto tutte le fasi, ma qui non c'è alcuna relazione tra loro, significa che le modifiche apportate alla configurazione precedente non si riflettono nei passaggi successivi. Un paio di problemi :
{$sort: {$dateFromString:{time: 1}}} // You can't use `$dateFromString` in sort stage. Also syntax of `$dateFromString` is incorrect.
Supponiamo che se ha funzionato (non lo farà ma presuppone ) non stai effettivamente convertendo time
&memorizzare il tempo convertito in una variabile per un uso successivo in $group
o fasi più in basso. Quindi devi salvarlo in una variabile nel rispettivo documento usando $addFields
o $project
. Non sono andato più in basso ma puoi provare sotto la query:
Query :
db.collection.aggregate([
/** sort on `time` field */
{ $sort: { time: 1 } },
/** Convert string format of `time` field to milliseconds & store to `convertedTime` field for each doc */
{ $addFields: { convertedTime: { $toLong: { $dateFromString: { dateString: "$time" } } } } },
/** Group without condition to push all documents into `docs` array */
{
$group: { _id: "", docs: { $push: "$$ROOT" } }
},
/** re-creating `docs` array */
{
$project: {
_id: 0,
docs: {
$reduce: {
input: { $slice: [ "$docs", 1, { $size: "$docs" } ] }, /** Pick `docs` array without first element for iteration */
initialValue: { docObj: [ { $arrayElemAt: [ "$docs", 0 ] } ], previousTime: { $arrayElemAt: [ "$docs.convertedTime", 0 ] } },
in: {
docObj: { $concatArrays: [ "$$value.docObj", [
{ $mergeObjects: [ "$$this", { time_difference: { $divide: [ { $subtract: [ "$$this.convertedTime", "$$value.previousTime" ] }, 1000 ] } } ] }
]
]
},
previousTime: "$$this.convertedTime" // Store current doc's time to `previousTime` to utilize for next record
}
}
}
}
},
{
$unwind: { path: "$docs.docObj" }
},
/** Remove additionally added field */
{
$project: { "docs.docObj.convertedTime": 0 }
},
/** Replace root of the doc with `docs.docObj` */
{
$replaceRoot: { newRoot: "$docs.docObj" }
}
])
Test : mongoplayground
Rif: aggregation-pipeline
Nota : Questa query non aggiungerebbe "time_difference" :null
per il primo documento, ma per ogni evenienza, provalo in initialValue
:docObj: [ {$mergeObjects :[ { $arrayElemAt: [ "$docs", 0 ] }, { "time_difference" :null } ] ]
. Inoltre suggerirei di limitare questa operazione ad alcuni documenti della collezione usando $match
come prima fase, invece di eseguire questa query su tutti i documenti causa
{
$group: { _id: "", docs: { $push: "$$ROOT" } }
}
di per sé sarà una cosa enorme quando verrà eseguito su un'intera raccolta con un enorme set di dati.