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);
}
}
}
Related
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 have the following database:
{ stream :{ "name": "name1",
"error1": 1,
"error2": 1,
"error3": 1 }
}
,
{ stream : {"name": "name1",
"error1": 2,
"error2": 1,
"error3": 1 }
}
,
{ stream : {"name": "name2",
"error1": 1,
"error2": 1,
"error3": 1 }
}
I would like to group it by name and sum every time some different combination of errors.
this is what I did in mongo, I need to create the following query dynamically in java
db.collection.aggregate([{$group: {_id: "$stream.name",error1: {$sum:"$stream.error1" },error2: {$sum: "$stream.error2" }} ])
the thing is that every time I need different combinations of the errors:error1 with error2, only error 1 etc..
this is what I did: (the arguments in the "if" are some boolean values that I am getting)
List<String> totalError = new ArrayList<String>();
BasicDBObject group = new BasicDBObject( "$group", new BasicDBObject("_id","$stream.name" ));
if (error1)
{
group.append("error1",new BasicDBObject ("$sum", "$stream.error1" ));
}
if (error2)
{
group.append("error2",new BasicDBObject ("$sum", "$stream.error2" ));
}
if (error3)
{
group.append("error3",new BasicDBObject ("$sum", "$stream.error3" ));
}
the problem is that I am getting:
{ "$group" : { "_id" : "$stream.name"} , "error1" : { "$sum: "$stream.error1"} , "error2" : { "$sum" : "$stream.error2"}
},
instead of:
{ "$group" : { "_id" : "$stream.name", "error1" : { "$sum: "$stream.error1"} , "error2" : { "$sum" : "$stream.error2"}}
if I knew what error combination I need I could use append in the constructor of group dbobject.. but I don't know the combination and I need to use the "ifs"
Try
BasicDBObject fields = new BasicDBObject("_id","$stream.name" );
if (error1)
fields.append("error1",new BasicDBObject ("$sum","$stream.error1"));
if (error2)
fields.append("error2",new BasicDBObject ("$sum","$stream.error2"));
if (error3)
fields.append("error3",new BasicDBObject ("$sum","$stream.error3"));
BasicDBObject group = new BasicDBObject( "$group", fields);
You should use helper functions when possible.
List<BsonField> fieldAccumulators = new ArrayList<>();
if (error1)
fieldAccumulators.add(Accumulators.sum("error1","$stream.error1"));
if (error2)
fieldAccumulators.add(Accumulators.sum("error2","$stream.error2"));
if (error3)
fieldAccumulators.add(Accumulators.sum("error3","$stream.error3"));
collection.aggregate(Arrays.asList(Aggregates.group("$stream.name", fieldAccumulators)));
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 am new to Mongodb. I have the following dataset in mongodb.
{
"_id": {
"$oid": "563644f44b17ca12886440a9"
},
"data": [
{
"uid": 1,
"character": " ",
"unicode": 32,
"color": -7309587
},
{
"uid": 2,
"character": "!",
"unicode": 33,
"color": -8911704
},
{
"uid": 3,
"character": "\"",
"unicode": 34,
"color": -1778539
}
I am trying to retrieve the color from this field using the _id and character. I am not able to execute the query.
This is what I tried.
DBObject clause1 = new BasicDBObject("_id",new ObjectId(KEY1));
DBObject clause2 = new BasicDBObject("data.character",text[i]);
BasicDBList or = new BasicDBList();
or.add(clause1);
or.add(clause2);
DBObject query = new BasicDBObject("$and", or);
Also I am having a lot of issues in finding ways to query in mongodb-java for the 3.0.0+ api. Could someone please help?
MongoClient mongoClient = new MongoClient(new ServerAddress("localhost", 27017));
MongoDatabase db = mongoClient.getDatabase("testDB");
AggregateIterable<Document> iterable = db.getCollection("testCollection").aggregate(
asList(new Document("$unwind", "$data"), new Document("$match", (new Document("_id", new ObjectId(
"5636f106b2acf98ecb033b98")).append("data.character", " "))), new Document("$project",
new Document("data.color", 1).append("_id", 0))));
iterable.forEach(new Block<Document>()
{
#Override
public void apply(final Document document)
{
System.out.println(document.toJson());
}
});
For more details check MongoDB Documentation.
A simple solution
In your document,
oid is an unique key for each document and hence your query should be like this
DBObject query = new BasicDBObject("_id.oid", KEY1);
// Query with value - DBObject query = new BasicDBObject("_id.oid","563644f44b17ca12886440a9");
Assign this to a cursor as shown below
DBCollection coll = db.getCollection("mycollection");
DBCursor cursor = coll.find(query);
Iterate the collection and retrieve your desired value.
I am new to MongoDB, I want to remove an element from array structure as shown below:
{
"Data" : [
{
"url" : "www.adf.com"
"type":7
},
{
"url" : "www.pqr.com"
"type":2
}
{
"url" : "www.adf.com"
"type":3
},
{
"url" : "www.pqr.com"
"type":5
}
],
}
I want to remove url=www.adf.com which has type as lowest values i.e in this document my query should remove type=3 and return document as below:
{
"Data" : [
{
"url" : "www.adf.com"
"type":7
},
{
"url" : "www.pqr.com"
"type":2
}
{
"url" : "www.pqr.com"
"type":5
}
],
}
The query shown by #shakthydoss can be described in java as follows:
MongoClient mongoClient = new MongoClient("SERVER", 27017);
DB db = mongoClient.getDB("DB_NAME");
DBCollection coll1 = db.getCollection("COLLECTION_NAME");
DBObject eleMatch = new BasicDBObject();
eleMatch.put("url", "www.pqr.com");
eleMatch.put("type", new BasicDBObject("$lte", 50));
BasicDBObject up = new BasicDBObject();
up.put("$elemMatch", eleMatch);
BasicDBList basicDBList = new BasicDBList();
basicDBList.add(up);
DBObject query = new BasicDBObject("Data", new BasicDBObject(" $all", basicDBList));
coll1.find(query);
Use $all with $elemMatch
If the field contains an array of documents, you can use the $all with the $elemMatch operator.
db.inventory.find( {
Data: { $all: [
{ "$elemMatch" : { url : "www.pqr.com": "M", type: { $lte: 50} } },
] }
} )