Reputation: 93
I recently started using MongoDB to save data from a project, the basic idea is the following.
On the server side I receive some JSON objects on a WebSocket and store it in the database.
The data I receive looks something like this:
{
{ident: "message_1"},
data:
[
{id: "data_1", value : 10},
{id: "data_2", value : 20},
{id: "data_3", value : 40},
{id: "data_4", value : 60},
{id: "data_4", value : 60},
],
timestamp : 12234456
}
And I'm currently saving the entire JSON object in the database.
The server also should handle user http requests where it queries the database for the requested data. The user requests are always for one element of the data
array and the timestamp. Thus the server response should look like this:
{ id: "data_1", value : 10, timestamp : 12234456}
I tried using db.collection.find with $elemMatch but my output still contains the data
array and the desired element.
{
data:
[{
id: "data_1",
value: 10
}],
timestamp : 12234456
}
So my question is if there's any possibility to query the database and return only the desired element of ´data´ array combined with the timestamp or I'll need re-create the response JSON object after reading the database.
Kind regards.
Upvotes: 1
Views: 717
Reputation: 93
Although @varman answer is correct for the question, to better match my case where the array data
will have a lot of elements (over 100), as @varman in the comment ´unwind´ can be expensive specially when the array contains loads of elements. So the ideal case I would prefer doing the ´unwind´ when the array only contains de desired element, to achieve that I changed the orders to the following:
"$match
To get only the documents with the desired data
element{ "$match": { "data.id": "data_1" } }
$project
and $filter
to filter out the unwanted elements from data $project: {
data: {
$filter: {
input: "$data",
as: "data",
cond: {$eq: ["$$data.id", "data_1"]}
}
},
"timestamp": 1,
"_id": 0
}
timestamp
field as in the correct answer { $addFields: {"data.timestamp": "$timestamp"} }
unwind
to deconstructs data
array field from the input documents to output a document for each element. {
$unwind: "$data"
}
$replaceRoot
replaces the input document with the data
fields.{"$replaceRoot": {"newRoot": "$data"}}
Hope this will be usefull to anyone needing to do the same, and if you have any recommendation/improvements on my current setup please I'm in for advices as I'm new to MongoDB.
Running example Mongo Playground
Upvotes: 0
Reputation: 8894
Welcome to the mongo world. You can easily achieve this with aggregations
$uwnind
to deconstruct the array$match
to get the desire value$addFields
to add new field to the object$replaceRoot
to make the object as rootHere is the code
db.collection.aggregate([
{ "$unwind": "$data" },
{ "$match": { "data.id": "data_1" } },
{ "$addFields": { "data.timestamp": "$timestamp" } },
{ "$replaceRoot": { "newRoot": "$data" } }
])
Working Mongo playground
Upvotes: 2