I am using Mongo Java Driver, and I am trying to use filters on the collection.find() function. For example, when I have a key which is a java object, the class of which contains certain fields:
Document document = (Document) collection.find(and(
eq("m_seniority", key.getM_seniority()),
eq("m_currency",key.getM_currency()),
eq("m_redCode",key.getM_redCode()),
eq("m_companyId",key.getM_companyId())
)).first();
I use the above command. But when I want to do that in bulk, I am being passed a collection of keys, ( Collection keys ), I can't access particular variables of the java objects inside as below:
List<Document> docs = (List<Document>) collection.find(and(
eq("m_seniority", keys.getM_seniority()),
eq("m_currency",keys.getM_currency()),
eq("m_redCode",keys.getM_redCode()),
eq("m_companyId",keys.getM_companyId())
)).into(new ArrayList<Document>());
Because getters are not of the collection, but just the objects, i can't use getters on the collection. How do I do this?
To create an or query on all of the Collection keys:
List<Bson> keyFilters = new ArrayList<>();
// for each key create an 'and' filter on seniority, currency, redcode and companyid
for (Key key : keys) {
keyFilters.add(
Filters.and(eq("m_seniority", key.getM_seniority()),
Filters.eq("m_currency",key.getM_currency()),
Filters.eq("m_redCode",key.getM_redCode()),
Filters.eq("m_companyId",key.getM_companyId())
)
);
}
List<Document> docs = (List<Document>) collection.find(
// 'or' all of the individual key filters
Filters.or(keyFilters)
).into(new ArrayList<Document>());
Related
I can find the answer (think?) for plain Mongodb querying, but nothing for Java for this particular use case...
I have a collection that is typed to the following object:
public class TestObj {
ObjectId id;
long value = 0;
// etc
}
I would like the sum of the value field across all objects held in the collection. How can I do this?
My current hangup is no matter wat I do, the aggregate method from the collection returns the type TestObj, and not a more generic object with the answer I seek. I have tried project, but didn't seem to have any effect.
Current code:
public long getTotalValue(){
Object returned = this.getCollection().aggregate(
List.of(
Aggregates.group(null, Accumulators.sum("$value", 1))
)
);
//TODO:: get sum
return 0L;
}
If you want to count how many collections have the value field you can use count in aggregation.
But if you want the sum of the values that the value field has in your collections you can calculate it like this with mongoDb aggregation
Arrays.asList(new Document("$group",
new Document("_id",
new BsonNull())
.append("value",
new Document("$sum", "$value"))))
value is the name of your field in the collection.
Full example:
Document returned = this.getCollection().aggregate(
List.of(new Document(
"$group",
new Document(
"_id",
new BsonNull()
)
.append(
"value",
new Document("$sum", "$numExpired")
)
)),
Document.class
).first();
return returned.getLong("value");
I need to create a mongotemplate database query to get a specific number of elements into a list.
At the moment I just get all the elements with findAll(), and then I modify the obtained data using code that I have writen within the service class.
Initially, I have a Laptop class with fields price::BigDecimal and name::String and I use findAll() to get a list of them.
Then I put those in a HashMap, where key is the name field, sorted from most expensive to cheapest.
Map<String, List<Laptop>> laptopsMap = laptopsFrom.stream()
.collect(Collectors.groupingBy(Laptop::getName,
Collectors.collectingAndThen(Collectors.toList(),
l -> l.stream()
.sorted(Comparator.comparing(Laptop::getPrice).reversed())
.collect(Collectors.toList())
))
);
So the results are like below:
[{"MSI", [2200, 1100, 900]},
{"HP", [3200, 900, 800]},
{"Dell", [2500, 2000, 700]}]
Then, I use the code in the bottom of the question, to create a Laptop list with the following contents:
[{"HP", 3200}, {"Dell", 2500}, {"MSI", 2200},
{"Dell", 2000}, {"MSI", 1100}, {"HP", 900},
{"MSI", 900}, {"HP", 800}, {"Dell", 700}]
So basically, I iterate the map and from each key, I extract the next in line element of the list.
do {
for (Map.Entry<String, List<Laptop>> entry :
laptopsMap.entrySet()) {
String key = entry.getKey();
List<Laptop> value = entry.getValue();
finalResultsList.add(value.get(0));
value.remove(0);
if (value.size() == 0) {
laptopsMap.entrySet()
.removeIf(pr -> pr.getKey().equals(key));
} else {
laptopsMap.replace(key, value);
}
}
} while(!laptopsMap.isEmpty());
I instead of all this in-class code need to use a mongoTemplate database argument, but I cant seem to figure out how to create such a complex query. I have read material about Aggregation but I have not found anything helpful enough. At the moment, I have started putting a query together as shown below:
Query query = new Query();
query.limit(numOfLaptops);
query.addCriteria(Criteria.where(Laptop.PRICE).gte(minPrice));
I want to get only the single value from Mongodb Collection.
Currently i am getting the Document which is FindIterable.
CustomObject obj = db
.getCollection("Collection",CustomObject.class)
.find(and(eq("field1", new BigDecimal(10409)),eq("field2", new BigDecimal(1))));
But , i dont want any result in to the Object or List.like in Oracle we use Query to get single Object :
SELECT NAME FROM EMPLOYEE_TABLE WHERE ID=10 AND DEPT_ID=23;
This query gives us the Single name of the employee on the basis of filter conditions, and we get the output in String type Object.
Same i want to get from the mongodb , i don't want to use any bean to populate the data. i want only single String object as result.
You may use the find method on Collection, passing a query and fields to retrieve:
BasicDBObject fields = new BasicDBObject();
fields.put("name", true);
BasicDBObject query = new BasicDBObject();
query.put("id", 13);
query.put("dept_id", 23);
DBCursor find = mongoTemplate.getCollection("example").find(query, select);
List<DBObject> list = find.toArray();
List<String> names = list.stream().map(o -> String.valueOf(o.get("name"))).collect(Collectors.toList());
If you are seeking for a function that returns just one document, then you can use findOne.
I want to execute a query in java where path and _id are two fields of the mongo document.
I want to get results list where these two fields are equal in the document.
I have tried using the following query.But could not retrieve the results properly.Received empty list which is not the case.
List<Metadata> MetadataList= ops.find(new Query(Criteria.where("path").is("_id")), Metadata.class);
How to get results where two field values are equal in mongo.
What you are looking for is the $where operator in MongoDB. Standard query operations do not compare the values of one field against another. In order to do this, you need to employ the JavaScript evaluation server side which can actually compare the two field values:
BasicQuery query = new BasicQuery(
new BasicDBObject("$where", "return this._id == this.path")
);
<Metadata> MetadataList = ops.find(query, Metadata.class);
Or you can do the same thing with native operators through the $redact pipeline stage available to the aggregation framework.
Pretty sure there is no $redact support in spring mongo as yet, but you can wrap the aggregation operation with a class to do so:
public class CustomAggregationOperation implements AggregationOperation {
private DBObject operation;
public CustomAggregattionOperation (DBObject operation) {
this.operation = operation;
}
#Override
public DBObject toDBObject(AggregationOperationContext context) {
return context.getMappedObject(operation);
}
}
And use it like this:
Aggregation aggregation = newAggregation(
new CustomAggregationOperation(
new BasicDBObject(
"$redact",
new BasicDBObject("$cond",
new BasicDBObject()
.append("if", new BasicDBObject(
"$eq", Arrays.asList("$_id", "$path")
))
.append("then", "$$KEEP")
.append("else", "$$PRUNE")
)
)
)
);
AggregationResults<Metadata> results = ops.aggregate(
(TypedAggregation<Metadata>) aggregation, Metadata.class);
So basic MongoDB query operations do not compare field values against each other. To do this you need to follow one of the methods here.
You can use BasicDBObject to add condition.
Try something
BasicDBObject query = new BasicDBObject("path", new BasicDBObject("$eq", "_id");
collection.find(query);
Please refer the below link for more information
http://mongodb.github.io/mongo-java-driver/2.13/getting-started/quick-tour/
I want to store multiple custom key and value pair on Google Datastore entity inside the another model as a child entity. I found that there are two ways to do it
HashMap<String, String> map = new HashMap<String, String>()
(or)
List<KeyValuePair> pairs = new ArrayList<KeyValuePair>()
I really do not know which is correct method.
I also wanted to search by key and value pair which will be specified by the user to get the parent entity. The search also can have multiple key and value pair.
Please help me do it.
Google AppEngine Datastore writes and reads only simple Java data types listed in the Java Datastore Entities, Properties, and Keys documentation, not HashMap<String,String> or List<KeyValuePair> collections. However, it is possible to iterate over these collections and store each member as a separate record. The Datastore uses either a String or a long integer as the key (also known as ID or name) for each record. Thus the best fit for your Java program would be a HashMap<String,String>.
As you're open to suggestions, how about using the Datastore low level API instead of JDO? Your requirement is lightweight and a low level implementation might be simpler. For example:
// Make up some sample data
java.util.HashMap<String,String> capitals = new java.util.HashMap<String,String>();
capitals.put("France","Paris");
capitals.put("Peru","Lima");
// Create the records
com.google.appengine.api.datastore.DatastoreService datastoreService;
datastoreService = com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService();
for (String country : capitals.keySet()) {
com.google.appengine.api.datastore.Entity capitalEntity;
capitalEntity = new com.google.appengine.api.datastore.Entity("Capitals", country);
capitalEntity.setUnindexedProperty("capital", capitals.get(country)); // or setProperty if you prefer
datastoreService.put(capitalEntity);
}
// Retrieve one record
String wantedCountry = "Peru", wantedCapital;
com.google.appengine.api.datastore.Query query;
com.google.appengine.api.datastore.PreparedQuery pq;
com.google.appengine.api.datastore.Entity entity;
com.google.appengine.api.datastore.Key wantedKey;
com.google.appengine.api.datastore.Query.Filter filter;
query = new com.google.appengine.api.datastore.Query("Capitals");
wantedKey = com.google.appengine.api.datastore.KeyFactory.createKey("Capitals", wantedCountry);
filter = new com.google.appengine.api.datastore.Query.FilterPredicate(
com.google.appengine.api.datastore.Entity.KEY_RESERVED_PROPERTY,
com.google.appengine.api.datastore.Query.FilterOperator.EQUAL,
wantedKey );
query.setFilter(filter);
pq = datastoreService.prepare(query);
entity = pq.asSingleEntity();
wantedCapital = (String) entity.getProperty("capital");
// Retrieve all records
java.lang.Iterable<com.google.appengine.api.datastore.Entity> entities;
java.util.Iterator<com.google.appengine.api.datastore.Entity> entityIterator;
query = new com.google.appengine.api.datastore.Query("Capitals");
pq = datastoreService.prepare(query);
entities = pq.asIterable();
entityIterator = entities.iterator();
while (entityIterator.hasNext()) {
entity = entityIterator.next();
String foundCountry = entity.getKey().getName();
String foundCapital = (String) entity.getProperty("capital");
// ... do whatever you do with the data
}