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 );
Related
I am using MongoDB Java Driver 3.6.3.
I want to create regex query with group by aggregation to retrieve distinct values.
Let's say I have json:
[{
"name": "John Snow",
"category": 1
},
{
"name": "Jason Statham",
"category": 2
},
{
"name": "John Lennon",
"category": 2
},
{
"name": "John Snow",
"category": 3
}]
I want to create query where regex is like "John.*" and group it by name so there would be only one "John Snow"
Expected result is:
[{
"name": "John Snow",
"category": 1
},
{
"name": "John Lennon",
"category": 2
}]
The answer provided by felix is correct, in terms of Mongo Shell commands. The equivalent expression of that command using the MongoDB Java driver is:
MongoClient mongoClient = ...;
MongoCollection<Document> collection = mongoClient.getDatabase("...").getCollection("...");
AggregateIterable<Document> documents = collection.aggregate(Arrays.asList(
// Java equivalent of the $match stage
Aggregates.match(Filters.regex("name", "John")),
// Java equivalent of the $group stage
Aggregates.group("$name", Accumulators.first("category", "$category"))
));
for (Document document : documents) {
System.out.println(document.toJson());
}
The above code will print out:
{ "_id" : "John Lennon", "category" : 2 }
{ "_id" : "John Snow", "category" : 1 }
You can achieve this with a $regex in $match stage, followed by a $group stage:
db.collection.aggregate([{
"$match": {
"name": {
"$regex": "john",
"$options": "i"
}
}
}, {
"$group": {
"_id": "$name",
"category": {
"$first": "$category"
}
}
}])
output:
[
{
"_id": "John Lennon",
"category": 2
},
{
"_id": "John Snow",
"category": 1
}
]
you can try it here: mongoplayground.net/p/evw6DP_574r
You can use Spring Data Mongo
like this
Aggregation agg = Aggregation.newAggregation(
ggregation.match(ctr.orOperator(Criteria.where("name").regex("john", "i")),
Aggregation.group("name", "category")
);
AggregationResults<CatalogNoArray> aggResults = mongoTemp.aggregate(agg, "demo",demo.class);
I have Collection as following. I have query this collection by user.
{
"user": "username",
"sites": {
"site": "abc",
"keywords": [
{
"keyword": "keyword1",
"dailyranks": [
{
"fild1": "value1"
},
{
"fild2": "value2"
},
{
"fild3": "value3"
},
]
},
{
"keyword": "keyword2",
"dailyranks": [
{
"fild1": "value1"
},
{
"fild2": "value2"
},
{
"fild3": "value3"
},
]
},
],
}
}
I want to get the result from the collection as follows, I want to get the last elements of keyword array in the collection
[
{
"keyword" : "keyword1"
"fild2" : "value2",
"fild3" : "value3"
},
{
"keyword" : "keyword2"
"fild2" : "value2",
"fild3" : "value3"
},
]
I have aggregate using $project, but didn't work out. help me to sort this out.
Code used-
BasicDBObject siteObject = new BasicDBObject();
siteObject.append("keywords", "$sites.keywords.keyword");
siteObject.append("lastrank", "$sites.keywords.dailyranks");
BasicDBList aDBList = new BasicDBList();
aaa.add(new BasicDBObject("user", modelLogin.getUSER_NAME()));
ArrayList<BasicDBObject> doc = new ArrayList<>();
doc.add(new BasicDBObject().append("$unwind", "$sites"));
doc.add(new BasicDBObject("$match", aDBList));
doc.add(new BasicDBObject().append("$project", siteObject));
AggregationOutput output = coll.aggregate(doc);
You can try below aggregation.
Use $map to transform the Keywords array.
Within $map, use $arrayElemAt to project the last and second last values from dailyranks and $let operator to hold the result from $arrayAtElem and project the fild value.
db.coll.aggregate({
$project: {
keywords: {
$map: {
input: "$sites.keywords",
as: "result",
in: {
keyword: "$$result.keyword",
fild2: {$let: {vars: {obj: {$arrayElemAt: ["$$result.dailyranks", -2]}},in: "$$obj.fild2"}},
fild3: {$let: {vars: {obj: {$arrayElemAt: ["$$result.dailyranks", -1]}},in: "$$obj.fild3"}}
}
}
}
}
})
Java Equivalent
MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("db")
MongoCollection<Document> collection = db.getCollection("collection");
List<Document> results =
collection.aggregate(
Arrays.asList(
Aggregates.match(Filters.eq("user", modelLogin.getUSER_NAME() )),
Aggregates.project(
Projections.fields(
new Document("keywords",
new Document("$map",
new Document("input", "$sites.keywords").
append("as", "result").
append("in",
new Document("keyword","$$result.keyword").
append("fild2",
new Document("$let",
new Document("vars", new Document("obj",
new Document("$arrayElemAt", Arrays.asList("$$result.dailyranks", -2)))).
append("in", "$$obj.fild2" ))).
append("fild3",
new Document("$let",
new Document("vars", new Document("obj",
new Document("$arrayElemAt", Arrays.asList("$$result.dailyranks", -1)))).
append("in", "$$obj.fild3" )))
)
)
)))
)).into(new ArrayList<>());
I am trying to execute the following query in java but it returns no results at all even though on command line it works fine! they are identical queries but different results!
BasicDBObject m_query = new BasicDBObject();
BasicDBObject cid = new BasicDBObject();
BasicDBList in = new BasicDBList();
in.add("56eea58b013693083806ab92");
cid.append("client_id", new BasicDBObject("$in", in));
BasicDBObject pcid = new BasicDBObject();
pcid.append("parent_client_id", new BasicDBObject("$in", in));
BasicDBList or = new BasicDBList();
or.add(cid);
or.add(pcid);
m_query.append("$or", or);
System.out.println(m_query);
System.out.println(mongoTemplate().getCollection(datatType).count(m_query));
The printed results are:
>{ "$or" : [ { "client_id" : { "$in" : [ "578ac9492c1ae71f2958d2c2"]}} , { "parent_client_id" : { "$in" : [ "578ac9492c1ae71f2958d2c2"]}}]}
> 0
When I execute the following on mongo cmd I get "5" as result for count:
> db.collection.count({$or : [ {client_id: {$in : ["578ac9492c1ae71f2958d2c2"]}}, {parent_client_id: {$in : ["578ac9492c1ae71f2958d2c2"]}} ]})
> {
"client_id": "56eea58b013693083806ab92",
"activity_type": "client",
"geo_tag": {
"type": "Point",
"coordinates": [
35.83278446,
31.97517983
]
},
"cell_phone": "",
"_platform": "web",
"client_status": "lead",
"phone": "",
"name": "client 2",
"comment": "undefined",
"zip_extension": "",
"contact_title": "",
"user": "Representative"
}
I have a mongoDB document with the following structure
{
"id": 9595511812,
"Feeds": [
{
"department": "mseb",
"consumer_number": 1234567890,
"due_date": "2016-11-11",
"due_amount": 400,
"balance_amount": 0,
"unitsConsumed": 40,
"freezeDate": "2016-11-11",
"lastPaidDate": "2016-11-11",
"billNumber": "9877",
"id": "1",
"paid": false
},
{
"department": "mseb",
"consumer_number": 1234567890,
"due_date": "2016-11-21",
"due_amount": 400,
"balance_amount": 0,
"unitsConsumed": 40,
"freezeDate": "2016-11-21",
"lastPaidDate": "2016-11-21",
"billNumber": "9877",
**"id": "2",**
"paid": false
}
]
}
I want to update paid == true for Feed with id=2 (** marked field above). How can I do that in using mongo java client?
I have tried
DB db = DBConnection.getDatabaseConnection();
DBCollection table = db.getCollection("customer");
BasicDBObject newDocument = new BasicDBObject();
newDocument.append("$set", new BasicDBObject().append("Feeds.paid", "true"));
BasicDBObject searchQuery = new BasicDBObject().append("id", "9595511812");
table.update(searchQuery, newDocument);
Feeds is an array, and you're updating the 2nd element, so the set would end with:
.append("Feeds.1.paid", "true"));
instead of:
.append("Feeds.paid", "true"));
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.