How to do this aggregation in Spring Data MongoDB? - java

I'm not used to work with Spring Data and I'm trying to do this MongoDB aggregation but I'm not able to solve the project and group part, match part was pretty easy:
db.collection.aggregate(
{ $match: { "car._id": "abc1234" } },
{
$project: {
month: { $month: "$day" },
year: { $year: "$day" },
services: 1
}
},
{
$group: {
_id: { month: "$month", year: "$year" },
total: { $sum: "$services" }
}
}
)
day is a Date type field. The query is working fine on the mongo shell, filtering by _id and grouping by year and months with the sum of all services (Int field). But I'm not able to implement it on Spring Data MongoDB.
I've tried with the Aggregation.group() but I'm getting lost because of the nested object in the _id.

as far as I know you must wrap everything in an array like so:
db.collection.aggregate([
{ $match: { "car._id": "abc1234" } },
{
$project: {
month: { $month: "$day" },
year: { $year: "$day" },
services: 1
}
},
{
$group: {
_id: { month: "$month", year: "$year" },
total: { $sum: "$services" }
}
}])

Related

How to get property value direct from mongodb in JAVA

Hi everyone I have a collection of documents like bellow. I want to directly get "rights" from roles array for params: _id, groups._id, roles._id using java mongo driver.
{
"_id": 1000002,
"groups": [
{
"_id": 1,
"roles": [
{
"rights": 3,
"_id": 1
},
{
"rights": 7,
"_id": 2
},
{
"rights": 3,
"_id": 3
}
]
}
],
"timestamp": {
"$date": {
"$numberLong": "1675267318028"
}
},
"users": [
{
"accessProviderId": 1,
"rights": 1,
"_id": 4
},
{
"accessProviderId": 1,
"rights": 3,
"_id": 5
}
]
}
I have AccessListItem class which represents this document and I have used Bson filters to get it from mongo, but after fetching i had to get information through java function.. I want to get int value directly from mongo base.
Bson fileFilter = Filters.eq("_id", itemId);
Bson groupFilter = Filters.elemMatch("groups", Document.parse("{_id:"+groupId+"}"));
Bson roleFilter = Filters.elemMatch("groups.roles", Document.parse("{_id:"+role+"}"));
Bson finalFilter = Filters.and(fileFilter, Filters.and(groupFilter,roleFilter));
MongoCollection<AccessListItem> accessListItemMongoCollection = MongoUtils.getAccessCollection(type);
AccessListItem accessListItem = accessListItemMongoCollection.find(finalFilter).first();
The short answer is you can't.
MongoDB is designed for returning documents, that is, objects containing key-value pairs. There is no mechanism for a MongoDB query to return just a value, i.e. it will never return just 3 or [3].
You could use aggregation with a $project stage at the end to give you a simplified object like:
{ rights: 3}
In javascript that might look like:
db.collection.aggregate([
{$match: {
_id: itemId,
"groups._id": groupId,
"groups.roles._id": role
}},
{$project: {
_id: 0,
group: {
$first: {
$filter: {
input: "$groups",
cond: {$eq: ["$$this._id",groupId]}
}
}
}
}},
{$project: {
"roles": {
$first: {
$filter: {
input: "$group.roles",
cond: { $eq: [ "$$this._id",role]}
}
}
}
}},
{$project: {
rights: "$roles.rights"
}}
])
Example: Playground
I'm not familiar with spring boot, so I'm not sure what that would look like in Java.

How to create a Java mongodb driver query that is identical to this mongodb update query with arrayfilter

Demo https://mongoplayground.net/p/_RyWWepvpyD.
I found examples to do with spring-mongodb. But unable to find any working way to do this with mongodb driver based code.
Query:
db.collection.update({
pollID: 123
},
{
"$inc": {
"answerAnalytics.$[element].selectCount": 1
}
},
{
"arrayFilters": [
{
"$or": [
{
"element.option": "1"
},
{
"element.option": "2"
}
]
}
],
"multi": true
})
DBCollectionFindAndModifyOptions dbCollectionFindAndModifyOptions = (new DBCollectionFindAndModifyOptions()).returnNew(true).upsert(false).update(incrObj).arrayFilters(arrayFilters);
dbCollection.findAndModify(queryDocument, dbCollectionFindAndModifyOptions);

Spring Data Mongo Aggregation Function with both $trim and $toLower

Trying to convert the following mongo query but cant find a solution to trim and toLower using Spring Aggregation queries
db.qabr.aggregate([
{ $match: {name: { "$ne": '' } }},
{ $group: {
_id: { 'name': { input: { $trim: { input: { $toLower : '$name' }}}}, 'qabrNumber': '$qabrNumber', 'qabristaan': '$qabristaan' }, // can be grouped on multiple properties
count: { "$sum": 1 }
}},
{ $match: {
count: { "$gt": 1 } // Duplicates considered as count greater than one
}
}
]
)
If I do the following:
AddFieldsOperation trimAndLowerName = Aggregation.addFields()
.addFieldWithValue("name", StringOperators.Trim.valueOf(
StringOperators.ToLower.lowerValueOf("name")
))
.build();
I keep getting 168 (InvalidPipelineOperator): 'Unrecognized expression '$trim'' on server
However running just trim or just toLower works:
AddFieldsOperation trimName = Aggregation.addFields()
.addFieldWithValue("name", StringOperators.ToLower.lowerValueOf("name"))
.build();

Convert mongoDB query into Spring Data MongoDB java code

I have the following MongoDB query and I dont know how to convert in Spring Data java code, the group and replaceRoot operations.
db.getCollection('operationData').aggregate([
{ $match: type: "OPERATION_CHEAP", amount: {$gte: 1000},
createdAt: {$gte: ISODate("2020-01-24T23:00:00.000Z")}
},
{ $project: { amount: 1, operationId: 1 } },
{ $sort: { amount: -1 } },
{ $group: { _id: '$operationId', g: { $first: {data: '$$ROOT'} }} }, <----
{ $replaceRoot: { newRoot: '$g.data' }}, <------
{ $sort: { amount: 1 } }
])
This is the code for the match operation:
Criteria criterias = new Criteria()
.andOperator(Criteria.where(Operation.AMOUNT)
.gte(minAmount)
.and(Operation.TYPE).is(OperationTypeEnum.CHEAP_OPERATION)
.and("createdAt").gte(startDate).lte(endDate));
MatchOperation matchOperation = Aggregation.match(criterias);
This is the code for the project operation:
ProjectionOperation projectionOperation = Aggregation.project("amount", "operationId");
And this is the Aggregation operation:
Aggregation aggregation = Aggregation.newAggregation(matchOperation, projectionOperation,
sort(direction, "amount"));
AggregationResults<OperationDataVO> aggregate = mongoTemplate.aggregate(aggregation,
COLLECTION, OperationDataVO.class);
I cant find out how to create and integrate the GroupOperation
Try this way:
Aggregation.group("operationId").first("$$ROOT").as("g");
Aggregation.replaceRoot("g");

Equivalent of $objectToArray using Mongodb java driver 3

I am moving a Mongodb query from Javascript to Java. The object format is as follows:
{
"record": {
"unknownName1": {
"count": 5,
"domain": "domain1"
}, {
...
}, {
"unknownNameN": {
"count": 3,
"domain": "domainN"
}
}
}
The Javascript query has the following portion:
[
{
$project: {
record: {
$objectToArray: "$record"
}
}
}, {
$unwind: { "$record"
}, {
$group: {
device: "$record.k"
},
count: {
$sum: "$record.v.count"
},
domain: {
$min: "$record.v.domain"
}
}
]
I have translated the above to use the Mongodb Java Driver 3 api and have the following:
List<Bson> query = Arrays.asList(
project(include("record")),
unwind("$record"),
group(computed("device", "$record.k"),
sum("count", "$record.v.count"),
min("domain", "$record.v.domain"))
);
The issue I am having is I can't seem to find an equivalent to $objectToArray using the Mongodb Java Driver and the subsequent sum and min operations depend on dot operating the k and v values generated from using $objectToArray.
Is there an equivalent way to map an object with unknown key names into the k and v format used by $objectToArray using the Mongodb Java Driver, preferrably version 3+?
Below will do.
project(computed("record", eq("$objectToArray", "$record")))

Categories

Resources