MongoDB deleting aggregated cells - mongodb

I have a problem.
I have collection of documents like this:
{
id (not _id),
type,
number
}
And what I want to do is aggregate cells with specific type and minimum number for this type for every id and delete them from this collection. Basically, single id can have few different number for specific type and I want to delete Document with the lowest value.
I tried to aggregate it using Java Driver 3 and mongoshell but I stucked on constructing it.

You can take reference from something like this
List<DBObject> pipeline=new ArrayList<DBObject>();
DBObject match = new BasicDBObject("$match", new BasicDBObject("date", sdf.format(new Date())).append("country", country).append("operator", operator).append("server_ip", server_ip));
DBObject unwind = new BasicDBObject("$unwind", "$details");
DBObject match2 = new BasicDBObject("$match", new BasicDBObject("details.type", "application_health"));
DBObject sort = new BasicDBObject("$sort", new BasicDBObject("details.datetime", -1));
DBObject limit = new BasicDBObject("$limit", 1);
pipeline.add(match);
pipeline.add(unwind);
pipeline.add(match2);
pipeline.add(sort);
pipeline.add(limit);
AggregationOutput outputoutput = collection.aggregate(pipeline);

Related

Mongo 3.6.3 java driver aggregate hint - returns undefined field 'hint'

I am trying to pass a hint on an aggregate in MongoDB Java Driver 3.6.3. The aggregate API allows for adding a hint as in:
MongoCollection<Document> coll = database.getCollection("myCollection")
ArrayList<BasicDBObject> docList = new ArrayList<BasicDBObject>();
BasicDBObject hint = new BasicDBObject("$hint","reportjob_customerId_1_siiDocumentAttributes.deleted_1");
MongoCursor<Document> cursor = coll.aggregate(docList).hint(hint).allowDiskUse(batchContext.isAllowDiskUse()).iterator();
I've tried with $hint and hint, but Mongo always returns Command failed with error -1: 'unrecognized field 'hint'
How do I properly send the hint on the aggregate call?
Looks like there is no support to pass the index name directly to hint. So you have pass the index creation document to the hint which you can get by name and use key to get the index document.
MongoCollection<Document> coll = database.getCollection("myCollection");
Bson index = coll.listIndexes().into(new ArrayList<>()).stream().filter(item -> item.getString("name").equals("reportjob_customerId_1_siiDocumentAttributes.deleted_1")).findFirst().get().getString("key");
List<BasicDBObject> docList = new ArrayList<BasicDBObject>();
MongoCursor<Document> cursor = coll.aggregate(docList).hint(index).allowDiskUse(batchContext.isAllowDiskUse()).iterator();
Legacy driver had support for both index name and document.
MongoClient client = new MongoClient();
DB database = client.getDB("myDatabase");
DBCollection coll = database.getCollection("myCollection");
List<BasicDBObject> docList = new ArrayList<BasicDBObject>();
AggregationOptions options = AggregationOptions.builder().allowDiskUse(batchContext.isAllowDiskUse()).build();
DBCursor dbCursor = ((DBCursor) coll.aggregate(docList, options)).hint("reportjob_customerId_1_siiDocumentAttributes.deleted_1");
You can create a jira to have the option to pass index name in the new driver here

Specify datatypes while updating MongoDB document using Casbah

I have a MongoDB document that I need to update using Casbah for scala. My mongoDB document looks like
{"_id": ObjectId("58d86364fbb1bb2224cab56a"),
"record_interval":
[
{
"record_time": ISODate("2017-01-26T09:22:15.000Z"),
"insert_time": ISODate("2017-03-26T12:57:08.610Z"),
"reading1": 50.0,
"reading2": 627.0
}
],
"record_id": "1234",
"record_hour": ISODate("2017-01-26T09:00:00.000Z")
}
I inserted the above document using df.write methodology, so I was able to specify the schema with datatypes when I created the dataframe and was able to successfully insert the document with the the specified datatypes.
Now, I need to add an object inside the record interval array. I have a JSON string that I parsed as a DBObject
val DBobject: DBObject = JSON.parse(Json_String).asInstanceOf[DBObject]
The DBobject that looks like below
{
"vib_temp": "55.0",
"vib_voltage": "647.0",
"message_time": "2017-01-26 03:48:52.000000",
"etl_date_time": "2017-03-26 06:57:09.302000"
}
I added this DBObject into the record_interval array of the aforementioned document using the below code.
collection.update(MongoDBObject("_id" -> new ObjectId("58d86364fbb1bb2224cab56a"))
,$push("record_interval" -> new MongoDBObject(DBobject)))
I am able to update the desired document, but the datatypes of the elements record_time, insert_time, reading1 and reading2 are all strings. Whereas I would like to insert the object with appropriate datatypes. How do I specify the datatypes while updating the document? Thanks in advance
I found that the DBObject that I am trying to insert should have the values with the desired data type.
Following worked for me.
val Current_datetime = new DateTime()
val message_time = new DateTime()
collection.update(MongoDBObject("_id" -> new ObjectId("58d86364fbb1bb2224cab56a"))
,$push("record_interval" -> new MongoDBObject(
,("vib_temp"->55.0)
,("vib_voltage"->647.0)
,("message_time"->message_time)
,("etl_date_time"-> Current_datetime))))

How to use DBObject Query in distinct function of mongo template?

i want to find distinct value of a field with some Query criteria. my code is..
public List searchservice(String th_type) {
Query query = new Query();
query.addCriteria(Criteria.where("th_type").regex(th_type));
List list = operations.getCollection("doclist").distinct("th_type", query);
return list;
}
in mongo template a distinct function is defined
mongoTemplate.getCollection(collection).distinct(key, query)
bu my code is giving error because i am using simple Query object instead of DBObject Query. how can i use DBObject Query here?
Use a BasicDBObject for this:
public List searchservice(String th_type) {
BasicDBObject dbObject = new BasicDBObject();
dbObject.append("th_type", th_type);
DBCollection dBCollection = operations.getCollection("doclist");
List list = dBCollection.distinct("th_type", dbObject);
return list;
}
UPDATE:
With regex:
BasicDBObject regexQuery = new BasicDBObject();
regexQuery.put("th_type", new BasicDBObject("$regex", th_type));
List list = operations.getCollection("doclist").distinct("th_type",regexQuery);

Java code for mongodb aggregation query

I am new to Java.
I checked few examples having aggregate usage.But still having few doubt.
db.employee.aggregate({$unwind: '$dp.fin.Record'},
{$match:{"dp.mon":"patch.metrics",'dp.fin.Record':{$exists:1}}},
{$group:{_id: '$dp.fin.Record', count:{$sum:1}}},
{$project:{count:'$count'}}, {$group:{_id:'Total
Count',total:{$sum:'$count'}}});
Can anybody help me writing java equivalent.
I have doubt how can we pass multiple matching condition as I have shown above.
I am trying like below
BasicDBObject unwind = new BasicDBObject("$unwind",
"$dp.fin.Record"); DBObject match = new BasicDBObject("$match", new
BasicDBObjectBuilder(""));
I think this will help:
DBObject unwind = new BasicDBObject("$unwind", "$dp.fin.Record");
DBObject match = BasicDBObjectBuilder.start().push("$match")
.add("dp.mon", "patch.metrics")
.push("dp.fin.Record").add("$exists", true).get();
DBObject group1 = BasicDBObjectBuilder.start().push("$group")
.add("_id", "$dp.fin.Record")
.push("count").add("$sum", 1).get();
DBObject project= BasicDBObjectBuilder.start().push("$project")
.add("count", "$count").get();
DBObject group2 = BasicDBObjectBuilder.start().push("$group")
.add("_id", "Total Count")
.push("total").add("$sum", "$count").get();
// Suppose collection has been prepared
AggregationOutput aggr = collection.aggregate(Arrays.asList(unwind, match, group1, project, group2));
If you above query is correct. You could approach this below codes.
//Forming Unwind parts
DBObject unwind = new BasicObject("$unwind","$dp.fin.record");
//Forming Match parts
DBObject match = new BasicObject();
match.put("dp.mon","patch.metrics")
match.put("dp.fin.Record", new BasicDBObject("$exists",1));
//Forming Group parts
DBObject group1 = new BasicDBObject();
group1.put("_id", '$dp.fin.Record');
group1.put("count", new BasicDBObject("$sum", 1));
//Forming Project parts
DBObject project = new BasicDBObject();
project.put("count", '$count');
//Forming Group parts
DBObject group2 = new BasicDBObject();
group2.put("_id", 'Total Count');
group2.put("total", new BasicDBObject('$sum', '$count'));
/**
* Executing aggregation
*/
AggregationOutput output = mongoOperations.getCollection("employee").aggregate(unwind,
new BasicDBObject("$match",match),
new BasicDBObject("$group",group1),
new BasicDBObject("$project",project),
new BasicDBObject("$group",group2));
Hope this could help you.

Problems with aggregation in MongoDB

Im trying to learn how to make sql like queries in Mongo and found this aggregation framework, when i run the code the average always turns out "0" all though the 'columns' have numbers in them, if i understand it right mongoDB saves all values as a strings( the number where integers at first in my sql server database which i transferred to mongoDB) so i dont have to care about types really when working with MongoDB? Can someone see why my average function dont work? The ordered quantity has number between 1.000000 - 7.000000.
DBCollection order = db.getCollection("Orderstatus");
DBObject match = new BasicDBObject("$match", new BasicDBObject("Company", "100") );
DBObject fields = new BasicDBObject("Facility", 1);
fields.put("Ordered quantity", 1);
fields.put("_id", 0);
DBObject project = new BasicDBObject("$project", fields );
DBObject groupFields = new BasicDBObject( "_id", "$Facility");
groupFields.put("average", new BasicDBObject( "$avg", "$Ordered quantity"));
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output = order.aggregate( match, project,group );
System.out.println(output);
The thing is that i thought that the numbers would be as integers since i got them from my sql server database where they are stored as integers using the code below. I see now that i use getString() when getting the values, is that why the numbers are strings in mongodb? how can i get them as integers?? i really want to be able to manipulate them as numbers!
StringBuilder orderstatus = new StringBuilder();
orderstatus.append("SELECT * FROM dbo.fact_orderstatus");
PreparedStatement t = connect.prepareStatement(orderstatus.toString());
DBCollection orderstat = db.getCollection("Orderstatus");
ResultSet v = t.executeQuery();
ResultSetMetaData rsm = t.getMetaData();
int column = rsm.getColumnCount();
while (v.next()) {
BasicDBObject orderObj = new BasicDBObject();
for(int x=1; x<column +1; x++){
String namn= rsm.getColumnName(x);
String custNum = (v.getString(x));
if (custNum != null && !custNum.trim().isEmpty()
&& custNum.length() != 0)
orderObj.append(namn, custNum);
}
orderstat.insert(orderObj)
The reason this is happening is that MongoDB does care about types of values you save.
If you want to store numbers, make sure they are not quoted otherwise they become stored as strings and you lose ability to manipulate them as numbers.
Javascript also differentiates between numbers and string, but MongoDB supports more number types than simple JavaScript. You can read more here.