Mongo group by query convert into java - java

How should I convert below mongo query in java, I used mongo java driver
db.demo.aggregate([
// Unwind the array
{ "$unwind": "$iInfo" },
// Sort the array elements within documents
{ "$sort": { "_id": -1, "iInfo.ifout": -1 } },
// Take only the "first" array element per document
{ "$group": {
"_id": "$_id",
"Iifout": { "$first": "$iInfo.ifout" },
"Iiferror": { "$first": "$iInfo.iferror" },
"Iifdes": { "$first": "$iInfo.ifdes" },
"Iifin": { "$first": "$iInfo.ifin" }
}},
// Group to push those results as an array
{ "$group": {
"_id": "$_id",
"iInfo": {
"$push": {
"ifout": "$Iifout",
"iferror": "$Iiferror",
"Iifdes": "$Iifdes",
"Iifin": "$Iifin"
}
}
}}
])
I write java code as below but it not work properly
BasicDBObject cmdBody = new BasicDBObject("aggregate",
collectionRealtime.toString());
pipeline.add(new BasicDBObject("$limit", 10));
pipeline.add(new BasicDBObject("$unwind", "$iInfo"));
pipeline.add(new BasicDBObject("$sort", new BasicDBObject(
"iInfo.ifout", -1)));
cmdBody.put("pipeline", pipeline);
when I run above java code it shows me all my nested output with sort but not shows in group and limit not work it display all documents.

Related

How to get data from mongodb with duplicated parameters?

I have try to create criteria that fetch from data base items.
Here is the code that fetches items from mongo db:
public List<Location> findByListOfId(List<String> locationsIds){
Query query = new Query();
query.addCriteria(Criteria.where("id").in(locationsIds));
return template.find(query, Location.class);
}
here is Location class defenition:
#Document("loaction")
#Data
public class Location {
#Id
private String id;
private long order;
private Date createdAt;
private Date updatedAt;
}
And here is the value of input(List locationsIds) in findByListOfId function:
List<String> locationsIds = {"5d4eee8047206b6d2df212bb","5d4eee8047206b6d2df212bb","5d4eee8047206b6d2df212bb"}
as you can see the input contains the same value three times.
The result that I get from findByListOfId function is a single item with id equal to 5d4eee8047206b6d2df212bb,
while I need to get the numbers of items with the same id as a number of times that exists with in variable(in my case I expect 3 fetched items with id = 5d4eee8047206b6d2df212bb ).
Any idea how this query can be created?
Not sure why you want to do it, but you can do it this way (in Mongo Query Language, you can then translate it in Java).
MongoDB Playground
db.collection.aggregate([
{
$match: {
key: {
$in: [
"5d4eee8047206b6d2df212bb",
"5d4eee8047206b6d2df212bb",
"5d4eee8047206b6d2df212bb"
]
}
}
},
{
"$addFields": {
"itemsArray": [
"5d4eee8047206b6d2df212bb",
"5d4eee8047206b6d2df212bb",
"5d4eee8047206b6d2df212bb"
]
}
},
{
"$unwind": "$itemsArray"
},
])
Using aggregation pipeline, you will add the array as a field using $addFields and then $unwind it (will give you x number of times).
I agree with others it's not something you want to do in production code, but I find the question interesting.
#Yahya's answer works with an assumption that the $match stage returns exactly 1 document.
The more generic pipeline to fetch exact number of documents regardless of how unique the key is and how many duplicates are in the query https://mongoplayground.net/p/546QnaFn4lV :
db.collection.aggregate([
{
$limit: 1
},
{
$project: {
_id: 1,
list: [
"5d4eee8047206b6d2df212bb",
"5d4eee8047206b6d2df212bb",
"6d4eee8047206b6d2df212bc",
"7d4eee8047206b6d2df212bd"
]
}
},
{
"$unwind": "$list"
},
{
"$lookup": {
"from": "collection",
"localField": "list",
"foreignField": "key",
"as": "match"
}
},
{
$project: {
match: {
$cond: [
{
$eq: [
"$match",
[]
]
},
[
{
_id: null,
"key": "$list"
}
],
"$match"
]
}
}
},
{
"$replaceWith": {
$first: "$match"
}
}
])
The first $project passes the list of requested ids to mongo.
The last $project stage returns "null" for requested ids that don't have a matching document.
Here is an aggregate query with required result:
Consider a collection with these documents:
{ _id: 1, a: 11 }
{ _id: 2, a: 22 }
{ _id: 3, a: 99 }
The query in mongo shell with input documents:
var INPUT_IDS = [ 1, 2, 1, 1 ]
db.collection.aggregate([
{
$match: {
_id: { $in: INPUT_IDS }
}
},
{
$group: {
_id: null,
docs: { $push: "$$ROOT" }
}
},
{
$project: {
docs: {
$map: {
input: INPUT_IDS,
as: "inid",
in: {
$let: {
vars: {
matched: {
$filter: {
input: "$docs", as: "doc", cond: { $eq: [ "$$inid", "$$doc._id" ] }
}
}
},
in: { $arrayElemAt: [ "$$matched", 0 ] }
}
}
}
}
}
},
{
$unwind: "$docs"
},
{
$replaceWith: "$docs"
}
])
The output:
{ "_id" : 1, "a" : 11 }
{ "_id" : 2, "a" : 22 }
{ "_id" : 1, "a" : 11 }
{ "_id" : 1, "a" : 11 }

MongoDB $regex query for "end with" particular char

I am not able to remove object from an array named Matrix for a Key match
BasicDBObject where = new BasicDBObject();
where.put("INSTITUTION_ID", instid);
where.put("RuleID", ruleid);
BasicDBObject obj1 = new BasicDBObject();
obj1.put("Matrix.Key",new BasicDBObject("$regex","/"+json.getString("Code")+"$/"));
collection.update(where,new BasicDBObject("$pull", obj1));
The code above is not removing object from array. The structure of the array can be found below
"Matrix" : [
{
"Key" : "6M",
"value" : "Queue"
},
{
"Key" : "6N",
"value" : "Queue"
},
{
"Key" : "6O",
"value" : "Queue"
}]
Command-line client
I suggest that before writing queries in Java notation, you first test them in the mongo console, with the regular JavaScript syntax. The following query works for me.
Data
db.matrix.insert(
{
INSTITUTION_ID: 1,
RuleID: 2,
Matrix: [
{
"Key": "6M",
"value": "Queue"
},
{
"Key": "6N",
"value": "Queue"
},
{
"Key": "6O",
"value": "Queue"
}
]
})
Query
db.matrix.update(
{
INSTITUTION_ID: 1,
RuleID: 2,
},
{
$pull:
{
Matrix:
{
Key:
{
$regex: /M$/
}
}
}
})
Data after the update
{
"INSTITUTION_ID" : 1.0000000000000000,
"RuleID" : 2.0000000000000000,
"Matrix" : [
{
"Key" : "6N",
"value" : "Queue"
},
{
"Key" : "6O",
"value" : "Queue"
}
]
}
Java
I am not sure how this update query should be represented in Java, but try this:
BasicDBObject where =
new BasicDBObject()
.put("INSTITUTION_ID", instid);
.put("RuleID", ruleid);
BasicDBObject update =
new BasicDBObject("$pull",
new BasicDBObject("Matrix",
new BasicDBObject("Key",
new BasicDBObject("$regex",
java.util.regex.Pattern.compile(json.getString("Code") + "$")))));
collection.update(where, update);

Java mongodb - find then average

Okey, let's start. Imagine that we have the next mongo collection:
{
"city": "TWENTYNINE PALMS",
"loc": [-116.06041, 34.237969],
"pop": 11412,
"state": "CA",
"_id": "92278"
}
{
"city": "NEW CUYAMA",
"loc": [-74.823806, 34.996709],
"pop": 80,
"state": "CA",
"_id": "93254"
}
{
"city": "WATERBURY",
"loc": [-72.996268, 41.550328],
"pop": 25128,
"state": "CT",
"_id": "06705"
}
Notice that loc array is [latitude,longitude]
I would like to obtain using java mongo driver the "pop" average of the cities that have the altitude beetwen -75,-70.
So, using SQL I know that the query is:
SELECT avg(pop)
WHERE loc.altitude > -75 AND lloc.altitude < -70
I am very noob in mongodb, this is my current code:
BasicDBObject doc = new BasicDBObject("loc.0", new BasicDBObject("$gte",
-75).append("$lte", -70));
DBCursor cursor = collection.find(doc);
The previous code returns me all the documents that altitude are beetwen (-75,-70), but I do not know how to obtain the average,using mongo driver, I know that I can iterate over results using java..
Thank you
Use the aggregation framework with following aggregation pipeline (Mongo shell implementation):
db.collection.aggregate([
{
"$match": {
"loc.0": { "$gte": -75 },
"loc.1": { "$lte": 70 }
}
},
{
"$group": {
"_id": 0,
"average": {
"$avg": "$pop"
}
}
}
])
With the example above, this outputs to console:
/* 1 */
{
"result" : [
{
"_id" : 0,
"average" : 12604
}
],
"ok" : 1
}
With Java, this can be implemented as follows:
DBObject match = new BasicDBObject();
match.put("loc.0", new BasicDBObject("$gte", -75));
match.put("loc.1", new BasicDBObject("$lte", 70));
DBObject groupFields = new BasicDBObject( "_id", 0);
groupFields.put("average", new BasicDBObject( "$avg", "$pop"));
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output = collection.aggregate( match, group );

Extracting fields from JSON fields from mongodb

I want to extract all these places mentioned in "location" field and does not want the other fields in the below json.but can't be able to extract since it is nested..Can anyone help me?
DBCursor cursorTotal = coll.find(obje);
while (cursorTotal.hasNext()) {
DBObject curNext = cursorTotal.next();
System.out.println("data::"+curNext.get("list.myList.location");
}
My "curNext" gives output as::
{
"_id": {
"$oid": "51ebe983e4b0d529b4df2a0e"
},
"date": {
"$date": "2013-07-21T13:31:11.000Z"
},
"lTitle": "Three held for running CISF job racket",
"list": {
"myList": [
{
"location": "Germany"
},
{
"location": "Geneva"
},
{
"location": "Paris"
}
]
},
"hash": -1535814113,
"category": "news"
}
I want my output as
Germany,Geneva,Paris
I have been in a long wait here for an answer and finally I got what I was searching for...Just noting my answer so someone else can benefit from it
DBCursor cursorTotal = coll.find(obje);
while (cursorTotal.hasNext()) {
DBObject curNext = cursorTotal.next();
String res=curNext.toString();
JsonElement jelement = new JsonParser().parse(res);
JsonObject jobject = jelement.getAsJsonObject();
jobject = jobject.getAsJsonObject("list");
JsonArray jarray = jobject.getAsJsonArray("myList");
jobject = jarray.get(0).getAsJsonObject();
String result = jobject.get("location").getAsString();
System.out.println("all places::"+result);
}
For finding only locations you should used mongo aggregation, below query will fetch all lcoations array
db.collectionName.aggregate({
"$unwind": "$ner.nerList"
},
{
"$group": {
"_id": "$_id",
"location": {
"$push": "$ner.nerList.location"
}
}
},
{
"$project": {
"location": "$location",
"_id": 0
}
})
Unfortunately I don't know how to convert this in Java but, I find below links which helpfull to you for converting above query in java format
Mongo Java aggregation driver

How to get embedding elements in mongodb using Java

my json data is like bellow:
"scores": [
{
"type": "exam",
"score": 1
},
{
"type": "quiz",
"score": 2
},
{
"type": "homework",
"score": 3
},
{
"type": "homework",
"score": 4
}
]
I'm using below code to retrieve only score.
while(cursor.hasNext())
{
BasicDBObject acc=( BasicDBObject) cursor.next();
acc.get("scores");
for(int i=0;i<=acc.size();i++)
{
((BSONObject) acc.get(i)).containsField("score");
}
//System.out.println(acc);
}
I'm getting null point exception. What is wrong?
This is what you will have to do:
while(cursor.hasNext())
{
BasicDBObject acc=(BasicDBObject) cursor.next();
BasicDBList scores = (BasicDBList) acc.get("scores");
for(int i=0;i<scores.size();i++)
{
BasicDBObject score = (BasicDBObject) scores.get(i);
System.out.println(score.get("score"));
}
}
Few notes:
You need to loop the scores array (I assume it's array) and not the BasicDBObject itself. Hence you need to cast it to BasicDBList. Otherwise you will have to defend against Cast Exceptions
Java arrays elements are from 0...size()-1. So use < and not <= in your loop.

Categories