query to convert mongodb array to key value pair - mongodb

i need to create a mongodb query to convert an array into key-value
my document is like this:
{
"_id" : ObjectId("5c8718b9b5fe262104408374"),
"axis" : "x",
"message_time" : ISODate("2019-03-11T08:04:41.000Z"),
"x_axis" : [
0.9766,
1.9531,
2.9297,
3.9063,
4.8828,
5.8594,
6.8359,
7.8125,
8.7891,
],
"etl_date_time" : ISODate("2019-03-12T02:26:01.510Z")
}
i want to convert it to
{
"_id" : ObjectId("5c8718b9b5fe262104408374"),
"axis" : "x",
"message_time" : ISODate("2019-03-11T08:04:41.000Z"),
"x_axis" : 8.7891,
"etl_date_time" : ISODate("2019-03-12T02:26:01.510Z")
}
can anyone help me with the query?

You can use aggreggation framework to achieve this.
db.collection.aggregate([
{
$addFields: {
x_axis: {
$arrayElemAt: [
{
$slice: [
"$x_axis",
-1
]
},
0
]
}
}
}
])
If you need to perform an update on your collection, you can add an $out stage
Mongo playground

Related

How to reduce a list of documents into a list of values in MongoDB

I ran an aggregation pipeline with a lookup stage on my database filtering out the data that I need and joining it with the data from another collection. I have, in the end, received something like this:
{
"_id" : ObjectId("5e53b804a72bb4185c682a00"),
"sample_ids" : [
{
"sample" : ObjectId("5e4fac16ad485744e34a799c")
},
{
"sample" : ObjectId("5e4fac18eaf0df39564a799b")
},
{
"sample" : ObjectId("5e4fac19ad485744e34a799e")
},
{
"sample" : ObjectId("5e4fac16eaf0df39564a799a")
}
]
}
I'm wondering whether it is possible to "squeeze" or "reduce" the list of documents to a single list of values so that I receive something like this instead:
{
"_id" : ObjectId("5e53b804a72bb4185c682a00"),
"sample_ids" : [
ObjectId("5e4fac16ad485744e34a799c"),
ObjectId("5e4fac18eaf0df39564a799b"),
ObjectId("5e4fac19ad485744e34a799e"),
ObjectId("5e4fac16eaf0df39564a799a")
]
}```
Simply like this:
db.collection.aggregate([
{
$project: {
sample_ids: "$sample_ids.sample"
}
}
])

MongoDB $divide on aggregate output

Is there a possibility to calculate mathematical operation on already aggregated computed fields?
I have something like this:
([
{
"$unwind" : {
"path" : "$users"
}
},
{
"$match" : {
"users.r" : {
"$exists" : true
}
}
},
{
"$group" : {
"_id" : "$users.r",
"count" : {
"$sum" : 1
}
}
},
])
Which gives an output as:
{ "_id" : "A", "count" : 7 }
{ "_id" : "B", "count" : 49 }
Now I want to divide 7 by 49 or vice versa.
Is there a possibility to do that? I tried $project and $divide but had no luck.
Any help would be really appreciated.
Thank you,
From your question, it looks like you are assuming result count to be 2 only. In that case I can assume users.r can have only 2 values(apart from null).
The simplest thing I suggest is to do this arithmetic via javascript(if you're using it in mongo console) or in case of using it in progam, use the language you're using to access mongo) e.g.
var results = db.collection.aggregate([theAggregatePipelineQuery]).toArray();
print(results[0].count/results[1].count);
EDIT: I am sharing an alternative to above approach because OP commented about the constraint of not using javascript code and the need to be done only via query. Here it is
([
{ /**your existing aggregation stages that results in two rows as described in the question with a count field **/ },
{ $group: {"_id": 1, firstCount: {$first: "$count"}, lastCount: {$last: "$count"}
},
{ $project: { finalResult: { $divide: ['$firstCount','$lastCount']} } }
])
//The returned document has your answer under `finalResult` field

mongoDB distict problems

It's one of my data as JSON format:
{
"_id" : ObjectId("5bfdb412a80939b6ed682090"),
"accounts" : [
{
"_id" : ObjectId("5bf106eee639bd0df4bd8e05"),
"accountType" : "DDA",
"productName" : "DDA1"
},
{
"_id" : ObjectId("5bf106eee639bd0df4bd8df8"),
"accountType" : "VSA",
"productName" : "VSA1"
},
{
"_id" : ObjectId("5bf106eee639bd0df4bd8df9"),
"accountType" : "VSA",
"productName" : "VSA2"
}
]
}
I want to make a query to get all productName(no duplicate) of accountType = VSA.
I write a mongo query:
db.Collection.distinct("accounts.productName", {"accounts.accountType": "VSA" })
I expect: ['VSA1', 'VSA2']
I get: ['DDA','VSA1', 'VSA2']
Anybody knows why the query doesn't work in distinct?
Second parameter of distinct method represents:
A query that specifies the documents from which to retrieve the distinct values.
But the thing is that you showed only one document with nested array of elements so whole document will be returned for your condition "accounts.accountType": "VSA".
To fix that you have to use Aggregation Framework and $unwind nested array before you apply the filtering and then you can use $group with $addToSet to get unique values. Try:
db.col.aggregate([
{
$unwind: "$accounts"
},
{
$match: {
"accounts.accountType": "VSA"
}
},
{
$group: {
_id: null,
uniqueProductNames: { $addToSet: "$accounts.productName" }
}
}
])
which prints:
{ "_id" : null, "uniqueProductNames" : [ "VSA2", "VSA1" ] }

Using embedded documents in spring data aggregation

I have a MongoDB document like this example doc:
{
"_id" : "A",
"articleNumber" : "0123456",
"shopDependentProperties" :
{
"shop" : "DE",
"foo" : "foo",
"bar" : "bar"
}
}
and want to pull out the properties of shopDependentProperties, to have the following result
{
"_id" : "A",
"articleNumber" : "0123456",
"foo" : "foo",
"bar" : "bar"
}
In MongoDB Shell i can solve it this way:
db.test.aggregate(
[
{
$project:
{
_id : "$_id",
articleNumber : "$articleNumber",
foo:"$shopDependentProperties.foo",
bar:"$shopDependentProperties.bar"
}
}
]
)
But: In Spring Data MongoDB i can't extract the embedded document contents.
I tried many combinations, nothing worked. For example:
ProjectionOperation projection = Aggregation.project("_id");
projection.andExpression("shopDependentProperties.foo").as("foo");
projection.andExpression("shopDependentProperties.bar").as("bar");
System.out.println(projection.toDBObject(Aggregation.DEFAULT_CONTEXT));
will ignore the shopDependentProperties.shop stuff and just print out
{ "$project" : { "_id" : 1}}
Any suggestions?
Thx
Haven't tested this, but as of
http://docs.mongodb.org/manual/reference/operator/aggregation/project/
you specify included / excluded fields like this:
db.test.aggregate(
[
{
$project:
{
_id : "$_id",
articleNumber : 1,
"shopDependentProperties.foo": 1,
"shopDependentProperties.bar": 1
}
}
]
)
Further down they explain, how to include embedded documents in the projection result.
I know how to do it in MongoDB, the problem was about doing the same thing in Spring Data.
But it works the same way, why didn't I try that before?
Solution:
ProjectionOperation projection = Aggregation.project(
"brandName",
"$shopDependentProperties.foo",
"$shopDependentProperties.bar" );

Removing a (sub) array in MongoDB using $pull

So..I'm evaluating Mongodb for managing a bit of my JSON back end. I'm totally new to it and I had one problem that was just messy to do in code, so I thought — heck — let me check out to see if it's time to finally start using Mongo
I have a data structure that is approximately like this:
[
{
"_id" : ObjectId("526f59ee82f2e293f9833c54"),
"humans" : [
{
"serviceUsers" : [
{
"foo1" : "bar2",
"foo2" : "bar3"
},
{
"foo1" : "baz2",
"foo2" : "baz3"
}
]
}
]
}
]
And now I want to remove any serviceUsers array elements that have "foo1" equal to "baz2" so that ideally I would end up with this:
[
{
"_id" : ObjectId("526f59ee82f2e293f9833c54"),
"humans" : [
{
"serviceUsers" : [
{
"foo1" : "bar2",
"foo2" : "bar3"
},
]
}
]
}
]
I figured that $pull was the place to start. And I tried a bunch of contortions. If I'm in collection mytests, I tried
db.mytests.update({"humans.serviceUsers.foo1":"baz2"}, {$pull:{"humans.serviceUsers" : {"foo1":"baz2"}}}, {multi: true})
Which to my admittedly naive eye, seems like it should follow the $pull syntax:
db.collection.update( { field: <query> }, { $pull: { field: <query> } } );
Mongo doesn't complain. But it doesn't change the collection in any way, either.
I also tried
db.mytests.update({}, {$pull:{"humans.serviceUsers" : {"foo1":"baz2"}}}, {multi: true})
Which also failed.
Any suggestions are greatly appreciated.
Thus humans is also array, you should use positional $ operator to access serviceUsers array of matched humans element:
db.mytests.update({ "humans.serviceUsers.foo1" : "baz2" },
{ $pull: { "humans.$.serviceUsers" : { "foo1": "baz2" }}});