([{
$match: {
"Publication_Date": {
$gte: ISODate("2003-01-01T00:00:00.0Z")
},
}
}, {
$group: {
_id: {
$year: "$Publication_Date"
},
total: {
$sum: 1
},
}
}])
Just "translate" this into org.bson.Document structure (similar to map) and call proper action (it is not a query, in that case it is an aggregate):
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("2003-01-01");
Document group = new Document();
group.put("_id", new Document("$year", "$Publication_Date"));
group.put("total", new Document("$sum", 1));
AggregateIterable<Document> aggregate = collection.aggregate(Arrays.asList(
new Document("$match", new Document("Publication_Date",
new Document("$gte", date))),
new Document("$group", group)
));
or use com.mongodb.client.model package static methods (less verbose):
AggregateIterable<Document> aggregate = collection.aggregate(Arrays.asList(
Aggregates.match(Filters.gte("Publication_Date", date)),
Aggregates.group(
new Document("$year", "$Publication_Date"),
Accumulators.sum("total", 1))));
Related
I have only one collection in my Mongodb and that is as follows
[
{
"_id": {
"timestamp": 1626753855,
"date": "2021-07-20T04:04:15.000+00:00"
},
"metadata": [
{
"country": "Canada",
"authors": [
{
"author": "Test Author",
"Books": [
{
"name": "Sample Book",
"code": "JCAR"
}
]
}
]
}
]
}
]
The method I am using is as follows
private void updateAuthorsMetadata(AuthorMetadata authorMetadata) {
MongoCollection<Document> collection = mDatabase.getCollection(authorMetadataCollection);
Bson eqFilter = eq("metadata.country", "Canada");
FindIterable<Document> itrDoc = collection.find(eqFilter);
if (itrDoc.first() == null) {
Document document = new Document();
document.append("metadata",
Arrays.asList(new Document("country", authorMetadata.getCountry()).append("authors",
Arrays.asList(new Document("author", authorMetadata.getAuthorName()).append("Books",
Arrays.asList(new Document("name", authorMetadata.getBookName()).append("code",
authorMetadata.getBookCode())))))));
collection.insertOne(document);
} else {
Bson andFilter = and(eq("metadata.country", "Canada"),
eq("metadata.authors.author", "John Doe"));
FindIterable<Document> itrAndDoc = collection.find(docFilter);
if (itrAndDoc.first() == null) {
Document doc = new Document("author", "John Doe).append("Books",
Arrays.asList(new Document("name", "Some Book").append("code",
"SBD4")));
Bson update = push("metadata[].authors", doc);
UpdateResult result = collection.updateOne(eqFilter, update);
}
}
}
The issue I am facing is that when I update collection at
else block
then it is adding the document to the root instead of adding it to the authors array, as shown in the image below.
How I can update it at the proper location i.e. adding to "authors" array? I am using Java driver v-3.12.7.
Finally, I figured it out. Anyone out there struggling with same issue can refer to this method. The issue was positional operators, some forums says that multiple positional operators can't be used below v 3.x.x but I am using 3.12.x and still had this issue. I think the way I am doing is not best/optimal but it works and if anyone direct me to the right direction then it would be great.
private void updateAuthorMetadata(AuthorMetadata authorMetadata) {
MongoCollection<Document> collection = mDatabase.getCollection(authorMetadataCollection);
Bson bsonEqFilter = eq("metadata.country", authorMetadata.getCountry());
FindIterable<Document> itrDoc = collection.find(bsonEqFilter);
Document found = itrDoc.first();
if (found == null) {
Document document = new Document();
document.append("metadata",
Arrays.asList(new Document("country", authorMetadata.getCountry()).append("authors",
Arrays.asList(new Document("author", authorMetadata.getAuthor()).append("books",
Arrays.asList(new Document("name", authorMetadata.getBookName())
.append("code", authorMetadata.getBookCode())))))));
collection.insertOne(document);
} else {
Bson bsonAndFilter = and(eq("metadata.country", authorMetadata.getCountry()),
eq("metadata.authors.author", authorMetadata.getAuthor()));
FindIterable<Document> itrAndDoc = collection.find(bsonAndFilter);
if (itrAndDoc.first() == null) {
Document document = new Document("author", authorMetadata.getAuthor()).append("Books",
Arrays.asList(new Document("name", authorMetadata.getBookName()).append("code",
authorMetadata.getBookCode())));
Bson update = push("metadata.$.authors", document);
UpdateResult result = collection.updateOne(bsonEqFilter, update);
} else {
Bson bsonMoreAndFilter = and(eq("metadata.country", authorMetadata.getCountry()),
eq("metadata.authors.author", authorMetadata.getAuthor()),
eq("metadata.authors.books.code", authorMetadata.getBookCode()));
FindIterable<Document> itrMoreAndDoc = collection.find(bsonMoreAndFilter);
if (itrMoreAndDoc.first() == null) {
Document docBooks = new Document("name", authorMetadata.getBookName()).append("code",
authorMetadata.getBookCode());
Bson update = push("metadata.0.authors.$.books", docBooks);
UpdateResult result = collection.updateOne(bsonAndFilter, update);
}
}
}
}
I have a problem to query the mongoDB data. Here is the document:
{
productId:1,
warehouses:[
warehouseId:1,
productBatch:[
{
unitPrice:15.5,
quantity:1000,
expireSearchTimestamp:14145555545,
currentQuantity:50
},{
unitPrice:17.5,
quantity:1000,
expireSearchTimestamp:14145555545,
currentQuantity:50
}
]
]
}
and by code is
public List<ProductSearchResult> findCustomSearch(List<Integer> medicines,
List<Integer> warehousesIds, int quantity)
{
UnwindOperation unwind1 = Aggregation.unwind("warehouses");
UnwindOperation unwind2 = Aggregation.unwind("warehouses.productBatch");
ProjectionOperation project = Aggregation.project("warehouses.productBatch");
MatchOperation match = Aggregation.match(Criteria.where("productId").in(productIds)
.and("warehouses.warehouseId").in(warehousesIds)
.and("warehouses.productBatch.currentQuantity").gte(quantity));
SortOperation sort = Aggregation.sort(Direction.ASC, "productBatch.unitPrice");
LimitOperation limit = Aggregation.limit(3);
Aggregation aggregation = Aggregation
.newAggregation(unwind1, unwind2, project, sort, limit)
.withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).explain(true)
.cursor(new BasicDBObject()).build());
AggregationResults<ProductSearchResult> results = mongoTemplate.aggregate(aggregation,
"medicine", ProductSearchResult.class);
List<ProductSearchResult> mappedResults = results.getMappedResults();
return mappedResults;
}
this is the function output
[
{
"$unwind": "$warehouses"
},
{
"$unwind": "$warehouses.productBatch"
},
{
"$match": {
"productId": {
"$in": [
20,
21
]
},
"warehouses.warehouse_id": {
"$in": [
1,
2,
3,
4,
5
]
},
"warehouses.productBatch.currentQuantity": {
"$gte": 10
}
}
},
{
"$project": {
"medicine_search": "$warehouses.productBatch"
}
},
{
"$sort": {
"productBatch.unitPrice": 1
}
},
{
"$limit": 3
}
]
when I run this function I got empty list but according to mongo compass I got 3 element.
thanks
I don't know why this block of code not work but the following one is satisfy for me
public void finalTry(List<Integer> productIds,
List<Integer> warehousesIds, int q, int limitN)
{
DBCollection collection = mongoTemplate.getCollection("product");
DBObject limit = new BasicDBObject("$limit", limitN);
DBObject sort = new BasicDBObject("$sort",
new BasicDBObject("productBatch.unitPrice", 1));
DBObject unwind1 = new BasicDBObject("$unwind", "$warehouses");
DBObject unwind2 = new BasicDBObject("$unwind", "$warehouses.productBatch");
DBObject project = new BasicDBObject("$project",
new BasicDBObject("productBatch", "$warehouses.productBatch"));
DBObject match1 = new BasicDBObject("$match",
new BasicDBObject("productId", new BasicDBObject("$in", productIds)));
DBObject match2 = new BasicDBObject("$match", new BasicDBObject("warehouses.warehouseId",
new BasicDBObject("$in", warehousesIds)));
DBObject match3 = new BasicDBObject("$match", new BasicDBObject(
"warehouses.productBatch.currentQuantity", new BasicDBObject("$gte", q)));
List<DBObject> pipeline = Arrays.asList(match1, unwind1, match2, unwind2, match3, project,
sort, limit);
AggregationOutput output = collection.aggregate(pipeline);
for (DBObject d : output.results())
{
System.out.println(d)
}
}
Thanks
I am trying to convert a mongo aggregate query into java objects. When I am running the query in RoboMongo (tool), I get the result but converting into java objects gives empty results.
Mongo Query:
db.getCollection('wb_physicians').aggregate([
{
$match: {
$and: [
{ "product.mpoCode": "VA001"},
{ "product.npoCode": { $exists: true } }
]
}
},
{
"$project" : {
"product.specialties.code": 1,
"providerId": 1,
"product.code": 1,
"_id" : 0
}
},
{ "$unwind" : "$product.specialties" },
{
"$group" : {
"_id" : {
"providerId": "$providerId" ,
"productCode": "$product.code"
},
"specialityCodeList": { "$addToSet": "$product.specialties.code" }
}
}
])
Java Code:
private static AggregationOutput findProviderandSpecialty(DBCollection collection) {
DBObject match = new BasicDBObject("$match" ,
new BasicDBObject("$and", Arrays.asList(
new BasicDBObject("product.mpoCode" , "VA001").append("product.npoCode", "$exists: true")
))
);
DBObject project = new BasicDBObject("$project" ,
new BasicDBObject("product.specialties.code" , 1)
.append("providerId" , 1)
.append("product.code", 1)
.append("_id", 0)
);
DBObject unwind = new BasicDBObject("$unwind" , "$product.specialties");
DBObject group = new BasicDBObject("$group",
new BasicDBObject("_id", new BasicDBObject("providerId" , "$providerId"))
.append("specialityCodeList",
new BasicDBObject("$addToSet", "$product.specialties.code")
)
);
AggregationOutput output = collection.aggregate(match,project,unwind,group);
return output;
}
Could you please help me where I made the wrong mapping?
The problem is on the $match pipeline:
DBObject match = new BasicDBObject("$match" ,
new BasicDBObject("$and", Arrays.asList(
new BasicDBObject("product.mpoCode" , "VA001")
.append("product.npoCode", "$exists: true")
))
);
should be
DBObject match = new BasicDBObject("$match" ,
new BasicDBObject("$and", Arrays.asList(
new BasicDBObject("product.mpoCode" , "VA001"),
new BasicDBObject("product.npoCode",
new BasicDBObject("$exists", "true")
)
))
);
Nonetheless, you can do without the explicit $and logic by specifying a comma-separated expression of the documents as well as removing the $project pipeline before the $group
as it's rather unnecessary, so your revised pipeline could be run as:
db.getCollection('wb_physicians').aggregate([
{
"$match": {
"product.mpoCode": "VA001",
"product.npoCode": { "$exists": true }
}
},
{ "$unwind" : "$product.specialties" },
{
"$group" : {
"_id" : {
"providerId": "$providerId" ,
"productCode": "$product.code"
},
"specialityCodeList": { "$addToSet": "$product.specialties.code" }
}
}
])
And the final Java code:
private static AggregationOutput findProviderandSpecialty(DBCollection collection) {
DBObject match = new BasicDBObject("$match" ,
new BasicDBObject("product.mpoCode" , "VA001").append("product.npoCode",
new BasicDBObject("$exists", "true")
)
);
DBObject unwind = new BasicDBObject("$unwind" , "$product.specialties");
DBObject group = new BasicDBObject("$group",
new BasicDBObject("_id", new BasicDBObject("providerId" , "$providerId"))
.append("specialityCodeList",
new BasicDBObject("$addToSet", "$product.specialties.code")
)
);
List<DBObject> pipeline = Arrays.<DBObject>asList(match, unwind, group);
AggregationOutput output = collection.aggregate(pipeline);
return output;
}
I have a wierd problem. I have a query which I am sure it works, but when I translated it in Java it does not return anything.
The MongoDB query is:
db.births.aggregate([
{
"$match": {
"day" : "March_13",
"events.year": "1929",
"events.info": /American/
}
},
{ "$unwind": "$events" },
{
"$match": {
"day" : "March_13",
"events.year": "1929",
"events.info": /American/
}
},
{
"$group": {
"_id": "$_id",
"day": { "$first": "$day" },
"events": { "$push": "$events" }
}
}
])
The Java code is:
AggregateIterable<Document> result = mongoDatabase.getCollection(category).
aggregate(
Arrays.asList(
new Document("$match",
new Document("day", day).
append("events.year", year).
append("events.info", "/" + word + "/")),
new Document("$unwind", "$events"),
new Document("$match",
new Document("day", day).
append("events.year", year).
append("events.info", "/" + word + "/")),
new Document("$group",
new Document("_id", "$_id").
append("day", new Document("$first", "$day")).
append("events", new Document("$push", "$events")))));
Please have a look and tell me if the way I translated it into Java is wrong or there is something else.
Thank you!
In Java you can try this:
String m = "American";
DBObject eventInfoObject = new BasicDBObject(
"events.info",
java.util.regex.Pattern.compile(m)
);
This send to the MongoDB server the query { "events.info" : { "$regex" : "American"}}
In your code replace:
"/" + word + "/"
with:
java.util.regex.Pattern.compile(word)
I want to perform an aggregation in Mongo 3.2 as explained here, but in Java:
https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup
At the moment my query object in java is very simple:
Document query = new Document();
query.append("employeId", employeId);
In addition to filtering by employeId, I would like to join this collection with company (where employee.company_id = company.id)
How can I do that in Java? It seems like I cannot find documentation of this new Mongo feature.
EDIT
Example of Employee collection:
{
"id" : 1,
"name" : "John",
"lastName" : "Moore",
"age" : 44,
"companyId": 10
}
Example of Company collection:
{
"id" : 10,
"companyName" : "Microsoft",
"numEmployee" : 100
}
Example of output expected
{
"id" : 1,
"name" : "John",
"lastName" : "Moore",
"companyId" : 10,
"companyName" : "Microsoft"
}
Running the following aggregation pipeline should give you the needed result
pipeline = [
{
"$match": {
"_id": employeeId
}
},
{
"$lookup": {
"from": "company",
"localField": "companyId",
"foreignField": "_id",
"as": "company"
}
},
{
"$project": {
"name": 1,
"lastName": 1,
"companyId": 1,
"companyName": "$company.companyName"
}
}
];
db.employee.aggregate(pipeline);
Java test implementation
public class JavaAggregation {
public static void main(String args[]) throws UnknownHostException {
MongoClient mongo = new MongoClient();
DB db = mongo.getDB("test");
DBCollection coll = db.getCollection("employee");
// create the pipeline operations, first with the $match
DBObject match = new BasicDBObject("$match",
new BasicDBObject("_id", employeeId)
);
// build the $lookup operations
DBObject lookupFields = new BasicDBObject("from", "company");
lookupFields.put("localField", "companyId");
lookupFields.put("foreignField", "_id");
lookupFields.put("as", "company");
DBObject lookup = new BasicDBObject("$lookup", lookupFields);
// build the $project operations
DBObject projectFields = new BasicDBObject("name", 1);
projectFields.put("lastName", 1);
projectFields.put("companyId", 1);
projectFields.put("companyName", "$company.companyName");
DBObject project = new BasicDBObject("$project", projectFields);
List<DBObject> pipeline = Arrays.asList(match, lookup, project);
AggregationOutput output = coll.aggregate(pipeline);
for (DBObject result : output.results()) {
System.out.println(result);
}
}
}