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")))
Related
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.
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);
I have a requirement of fetching data from mongodb and being done using Java Spring Reactive Mongodb library. I am using the following code for this:
Criteria criteria = Criteria.where(QUERYFIELD1).in(listOfIds)
.andOperator(Criteria.where(QUERYFIELD2).gte(ChildDate));
Query query = Query.query(criteria).noCursorTimeout();
reactiveMongoTemplate.find(query, Document.class, COLLECTIONNAME);
Where QUERYFIELD1 is "ChildId" and QUERYFIELD2 is a "ChildDate". Following is the structure of my document:
{
"_id": {
"$oid": "6296968fa63757a93e1cd123"
},
"Level1": {
"Level2": [
{
"ChildId": "1234",
"ChildDate": {
"$date": "2021-04-01T04:00:00.000Z"
}
},
{
"ChildId": "5678",
"ChildDate": {
"$date": "2017-05-16T04:00:00.000Z"
}
},
{
"ChildId": "3456",
"ChildDate": {
"$date": "2008-09-16T04:00:00.000Z"
}
},
{
"ChildDate": {
"$date": "2022-06-01T04:00:00.000Z"
},
"ChildId": "7891"
}
]
}
}
I am trying to find a document which should match the criteria within the Objects under Level2. For e.g. if My criteria has ChildId as "3456" and ChildDate as "2022-06-01T04:00:00.000Z" then I should get empty results as ChildId is matching with Object3 and ChildDate is matching with Object4. But when I use below query, I get 1 record as the match:
{ "Level1.Level2.ChildId" : "3456", "Level1.Level2.ChildDate" : { $gt: new Date("2022-01-01T05:00:00.000+00:00")}}
I am trying to achieve this using Spring Reactive MongoDB. Please help.
You can use $elemMatch for finding the documents that their array includes an item which matches the conditions:
db.collection.find({
"Level1.Level2": {
$elemMatch: {
ChildId: "3456",
ChildDate: {$gt: new Date("2008-09-16T05:00:00.000Z")}
}
}
})
See how it works on the playground example
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();
I have two fields in my documents: ACount and BCount, I want to write a range query to get the documents where sum(ACount + BCount) > 100 through Java API. I was trying to do something like
BoolQueryBuilder.must(QueryBuilders.rangeQuery(...).gte(100)), but couldn't find a good way to do it. Does anyone know how to do this?
You need to use painless script for this.
{
"query": {
"bool": {
"filter": [
{
"script": {
"script": {
"source": "(doc['ACount'].value + doc['BCount'].value) > params.count",
"params": {
"count": 100
}
}
}
}
]
}
}
}
You can use java client generate the above query.