How to write the mongo aggregation match condition in Spring? - spring

My Aggregate query is like this:
{
"profile_id": "0f502f37-d9f3-4e18-ba1a-e5f9a54d4fcc",
"$or":[
{"$and": [{sleep:{$ne:null}},{
"device_type": "fitbit"
}]},
{"$and": [{activity:{$ne:null}},{
"device_type": "google_fit"
}]}
]
}
I want to achieve this in Spring boot how to achieve this?

Related

$elemMatch with $in SpringData Mongo Query

I am in the process of attempting to create a method that will compose a query using Spring Data and I have a couple of questions. I am trying to perform a query using top level attributes of a document (i.e. the id field) as well as attributes of an subarray.
To do so I am using a query similar to this:
db.getCollection("journeys").find({ "_id._id": "0104", "journeyDates": { $elemMatch: { "period": { $in: [ 1,2 ] } } } })
As you can see I would also like to filter using $in for the values of the subarray. Running the above query though result in wrong results, as if the $elemMatch is ignored completely.
Running a similiar but slightly different query like this:
db.getCollection("journeys").find({ "_id._id": { $in: [ "0104" ] } }, { journeyDates: { $elemMatch: { period: { $in: [ 1, 2 ] } } } })
does seem to yield better results but it returns the only first found element matching the $in of the subarray filter.
Now my question is, how can I query using both top level attributes as well subarrays using $in. Preferably I would like to avoid aggregations. Secondly, how can I translate this native Mongo query to a Spring data Query object?

#Query annotations in Spring Boot for elasticsearch to use Sort and Collapse

I have a question like can we use #Query annotations in elasticsearch to act as a nested query to use Sort and Collapse.
my query looks like this::
GET clean/_search
{
"query": {
"match_phrase_prefix":{
"search_term": "Monkey"
}
},
"sort": [
{
"search_score": {
"order": "desc"
}
}
],
"collapse":{
"field": "normalized_term"
},
"size": 10
}
This is the query, can I implement using #Query annotations and how can I implement this?
No, you'd need to use a NativeSearchQuery where you can set a sort and collapse. The #Query annotation on a method defines only the query part sent to Elasticsearch.

How do i put multiple conditions inside spring data mongodb aggregation filter?

Mongodb states that it is possible to put multiple conditions inside cond of filter. Like this:
{
$filter: {
input: [ 1, "a", 2, null, 3.1, NumberLong(4), "5" ],
as: "num",
cond: { $and: [
{ $gte: [ "$$num", NumberLong("-9223372036854775807") ] },
{ $lte: [ "$$num", NumberLong("9223372036854775807") ] }
] }
}
}
Source: - https://docs.mongodb.com/manual/reference/operator/aggregation/filter/
I would like to do the same inside spring data mongodb. I have this aggregation:
val aggregation = Aggregation.newAggregation(
project()
.and(
filter("some")
.`as`("some")
.by(
ComparisonOperators.Lte.valueOf("some.field").lessThanEqualToValue(2000)
/* here i would like to put "and" like .and(valueOf("some.field").greaterThanValue(1000) but it does not exists on returned value of valueOf*/
)
)
)
How can i do this ? I was looking for some "and" function on the level of "by" or "filter" but it does not exists. Adding another and will override my previous value (if for example i would like to filter using range of some.field or by multiple fields). How do i do this for multiple fields ?

Using subtract in a Spring MongoDB group aggregation

I have the following aggregation query that works when I use the command line in Mongo.
{'$group':
{ '_id':
{'serviceName': '$serviceName'},
'timeAverage':
{'$avg':
{'$subtract': ['$lastCheckTime', '$enqueuedTime']}
}
}
}
But as far as I can tell, in Spring MongoDB there is no support for doing "subtract" inside of an avg operation in a group operation.
How would I go about making this work?
You could try projecting the difference field first by using the SpEL andExpression in the projection operation and then use it in the avg accumulator in the group operation:
Aggregation agg = newAggregation(
project("serviceName")
.andExpression("lastCheckTime - enqueuedTime").as("interval")
group("serviceName")
.avg("interval").as("timeAverage")
);
or use the $subtract arithmetic aggregation operator which is supported in Spring Data MongoDB as minus()
Aggregation agg = newAggregation(
project("serviceName")
.and("lastCheckTime").minus("enqueuedTime").as("interval")
group("serviceName")
.avg("interval").as("timeAverage")
);
This translates to following native aggregation operation:
[
{
"$project": {
"serviceName": 1,
"interval": { "$subtract":[ "$lastCheckTime", "$enqueuedTime" ] }
}
},
{
"$group": {
"_id": "$serviceName",
"timeAverage": { "$avg": "$interval" }
}
}
]

How to use two conditon in one array?

I have a list of task stored in Mongo, like below
{
"name": "task1",
"requiredOS": [
{
"name": "linux",
"version": [
"6.0"
]
},
{
"name": "windows",
"version": [
"2008",
"2008R2"
]
}
],
"requiredSW": [
{
"name": "MySQL",
"version": [
"1.0"
]
}
]
}
My purpose is to filter the task by OS and Software, for example the user give me below filter condition
{
"keyword": [
{
"OS": [
{
"name": "linux",
"version": [
"6.0"
]
},
{
"name": "windows",
"version": [
"2008"
]
}
]
},
{
"SW": [ ]
}
]
}
I need filter out all the task can both running on the windows2008 and Linux 6.0 by searching the "requiredOS" and "requiredSW" filed. As you seen, the search condition is an array (the "OS" part). I have a trouble when use an array as search condition. I expect the query to return me a list of Task which satisfy the condition.
A challenging thing is that I need to integrate the query in to spring-data using #Query. so the query must be parameterized
can anyone give me a hand ?
I have tried a query but return nothing. my purpose is to use $all to combine two condition together then use $elemMatch to search the "requiredOS" field
{"requiredOS":{"$elemMatch":{"$all":[{"name":"linux","version":"5.0"},{"name":"windows","version":"2008"}]}}}
If I understood correctly what you are trying, you need to use $elemMatch operator:
http://docs.mongodb.org/manual/reference/operator/query/elemMatch/#op._S_elemMatch
Taking your example, the query should be like:
#Query("{'requiredOS':{$elemMatch:{name:'linux', version:'7.0'},$elemMatch:{name:'windows', version:'2008'}}}")
It match the document you provided.
You basically seem to need to translate your "parameters" into a query form that produces results, rather than passing them straight though. Here is an example "translation" where the "empty" array is considered to match "anything".
Also the other conditions do not "literally" go straight through. The reason for this is that in that form MongoDB considers it to mean an "exact match". So what you want is a combination of the $elemMatch operator for multiple array conditions, and the $and operator which combines the conditions on the same property element.
This is a bit longer than $all but essentially because that operator is a "shortened" form of $and as $in is to $or:
db.collection.find({
"$and": [
{
"requiredOS": {
"$elemMatch": {
"name": "linux",
"version": "6.0"
}
}
},
{
"requiredOS": {
"$elemMatch": {
"name": "windows",
"version": "2008"
}
}
}
]
})
So it just a matter of transforming the properties in the request to actually match the required query form.
Building this into a query object can be done in a number of ways, such as using the Query builder:
DBObject query = new Query(
new Criteria().andOperator(
Criteria.where("requiredOS").elemMatch(
Criteria.where("name").is("linux").and("version").is("6.0")
),
Criteria.where("requiredOS").elemMatch(
Criteria.where("name").is("windows").and("version").is("2008")
)
)
).getQueryObject();
Which you can then pass in to a mongoOperations method as a query object or any other method that accepts the query object.

Resources