Reputation: 15114
I have a collection containing objects like this one:
{
_id: '1234',
lines: [{
timestamp: 100,
data: {
prop1: 123,
prop2: 123,
prop3: 123
}
}, {
timestamp: 200,
data: {
prop1: 123,
prop2: 123,
prop3: 123
}
}, {
timestamp: 300,
data: {
prop1: 123,
prop2: 123,
prop3: 123
}
}]
}
I need to create a query to filter the lines in my object but I need to know what is the index of the object in the array. My query is like this:
collection.aggregateOne([
{ $match: { _id: queryId } },
{ $filter: { input: '$lines', as: 'line', cond: { $gt: ['$$line.timestamp', queryTimestamp ] } } }
]);
The query works, but I don't know what to write to have the array index of the lines in my output.
For example, if I'm looking for lines with a timestamp greater than 190
in my object, I want this output :
{
_id: '1234',
lines: [{
index: 1, // Index is 1 because the first element is filtered
timestamp: 200,
data: {
prop1: 123,
prop2: 123,
prop3: 123
}
}, {
index: 2,
timestamp: 300,
data: {
prop1: 123,
prop2: 123,
prop3: 123
}
}]
}
Is there a way to achieve that? I am using Mongodb 4.4.1.
Upvotes: 0
Views: 512
Reputation: 4452
If I understood the question correctly, author wants to add index in sequence for the filtered data, where the filter is timestamp
> 190
.
While the accepted answer seems to be correct w.r.t the data posted in the question, it wont work for below data:
{
"_id" : "1234",
"lines" : [
{
"timestamp" : 100,
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
}
},
{
"timestamp" : 200,
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
}
},
{
"timestamp" : 180, // <- 180 in between 200 and 300 will break the sequence
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
}
},
{
"timestamp" : 300,
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
}
}
]
}
Output based on accepted answer:
{
"_id" : "1234",
"lines" : [
{
"timestamp" : 200,
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
},
"index" : 1
},
{
"timestamp" : 300,
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
},
"index" : 3
}
]
}
So improving the answer by @prasad_:
const queryTimestamp = 190;
db.collectionName.aggregate([
{ $unwind: "$lines" },
{
$match: {
"lines.timestamp": { $gt: queryTimestamp }
}
},
{
$group: {
_id: "$_id",
"lines": { $push: "$lines" }
}
},
{
$addFields: {
"lines": {
$reduce: {
input: { $range: [0, { $size: "$lines" }] },
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
timestamp: { $arrayElemAt: ["$lines.timestamp", "$$this"] },
data: { $arrayElemAt: ["$lines.data", "$$this"] },
index: { $add: ["$$this", 1] }
}
]
]
}
}
}
}
}
]);
Output based on improved answer:
{
"_id" : "1234",
"lines" : [
{
"timestamp" : 200,
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
},
"index" : 1
},
{
"timestamp" : 300,
"data" : {
"prop1" : 123,
"prop2" : 123,
"prop3" : 123
},
"index" : 2
}
]
}
Upvotes: 0
Reputation: 14297
This aggregation query returns the desired output:
db.collection.aggregate([
{
$addFields: {
lines: {
$reduce: {
input: { $range: [ 0, { $size: "$lines" } ] },
initialValue: [ ],
in: {
$concatArrays: [
"$$value",
{
$let: {
vars: {
doc: { $arrayElemAt: [ "$lines", "$$this" ] }
},
in: {
$cond: {
if: { $gt: ['$$doc.timestamp', queryTimestamp ] },
then: [ { $mergeObjects: [ "$$doc", { index: "$$this"} ] }],
else: [ ]
}
}
}
}
]
}
}
}
}
}
])
Upvotes: 1