Finding distinct from collections in mongodb - java

Our previous implementation for finding distinct elements from a collection used to be :
List<String> names = mongoClient.getDB(dbName).getCollection(collectionName).distinct(NAME_KEY);
Trying to upgrade this into the current implementation with mongo 3.3.0+ as tried is :
List<String> names = mongoClient.getDatabase(dbName)
.getCollection(collectionName, TDocType.class)
.distinct(NAME_KEY, String.class); // compile error - required Class<TResult>
Have also given a try to
.distinct(NAME_KEY, TDocType.class) // doesn't work
What shall be the target type of the iterable in this case?
Edit - The question is not a duplicate of Get distinct records values since the implementation has changed over the upgrade of mongodb-java-driver.

You can try something like this.
DistinctIterable<String> iterable = mongoClient.getDatabase(dbName).
.getCollection(collectionName, TDocType.class).distinct(NAME_KEY, String.class);
MongoCursor<String> cursor = iterable.iterator();
List<String> list = new ArrayList<>();
while (cursor.hasNext()) {
list.add(cursor.next());
}

Related

Query dsl - Looping through a list to create OR predicates

How do I dynamically create "OR" predicates if I have a List<List<String>>
I am using query dsl and spring data.
QOrder order = QOrder.order;
JPQLQuery<Order> query = from(order);
query.where(order.status.eq("ready"));
List<List<String>> filterTypes;
This is what I am trying to do:
for(List<String> types : filterTypes) {
query.where(order.type.in(types));
}
So the result should be something like
select * from order o where o.status='ready' and (o.type in(t1,t2) or o.type in(t3,t4))
To directly answer your question: assuming you're using a relatively modern version of QueryDSL, you should be able to use a BooleanBuilder:
QOrder order = QOrder.order;
SQLQuery<Order> query = from(order);
query.where(order.status.eq("ready"));
// Example data
List<List<String>> filterTypes = ImmutableList.of(
ImmutableList.of("t1", "t2"),
ImmutableList.of("t3", "t4"));
BooleanBuilder builder = new BooleanBuilder();
for (List<String> types : filterTypes) {
builder.or(order.type.in(types));
}
query.where(builder);
Backing up, assuming your actual application data model is similar to the example you provided, this:
o.type in (t1,t2) or o.type in (t3,t4)
Is equivalent to:
o.type in (t1,t2,t3,t4)
You could translate your List<List<String>> into List<String> and do your type query update once:
QOrder order = QOrder.order;
SQLQuery<Order> query = from(order);
query.where(order.status.eq("ready"));
// Example data
List<List<String>> filterTypes = ImmutableList.of(
ImmutableList.of("t1", "t2"),
ImmutableList.of("t3", "t4"));
List<String> flatFilterTypes = filterTypes.stream().flatMap(List::stream).collect(Collectors.toList());
query.where(order.type.in(flatFilterTypes));
I suspect that your database's query optimizer would do the same thing for either query (you'd have to check a query execution plan to be sure), but it'd probably be more clear what's going on if you did simplified the query on the Java side rather than relying on the database query optimizer.

Consume the results of Neo4j driver in java

Using Neo4j driver for java, i want to send a search query to the database such as:
MATCH(a:`Label`{Property:"NODE_PROPERTY"})
RETURN *
First i create a session and the i use the run methods of the driver to run a query:
Result run = session.run(query);
run variable contains a list of Records. My question is how can i consume the records so that i can convert them to java objects? I tried to get the values of the results but since they're not iterable, it's not possible to get them one by one.
Result implements Iterator<Record>, so there is a bunch of ways of consuming it, e.g.:
While loop (Java 6 style):
Result result = session.run(query);
List<MyPojo> myList = new ArrayList<>();
while(result.hasNext()) {
Record r = result.next();
myList.add(mapToMyPojo(r));
}
Stream (Java 8+ style):
Result result = session.run(query);
List<MyPojo> myList = result.stream()
.map(record -> mapToMyPojo(record))
.collect(Collectors.toList());
Using Result.list(Function<Record,T> mapFunction):
Result result = session.run(query);
List<MyPojo> myList = result.list(r -> mapToMyPojo(r));
Mapping to a Java object is pretty stright-forward:
public MyPojo mapToMyPojo(Record record) {
MyPojo pojo = new MyPojo();
pojo.setProperty(record.get("Property").asString());
// ...
return pojo;
}
Although instead of mapping results manually, you might want to use neo4j-ogm

Find intersection between collections with different objects

I have list of custom objects like below:
List<CustomObject> existingValues
And another collection with ids that has been sent from client and contains ids of CustomObject mentoioned above Set<Long> ids.
My goal is to return collection with CustomObject that will contains only elements where ids intersect.
I can simply do this with nested for each cycles. But it looks a bit ugly.
In SQL I can do similar stuff with query:
select * where customobject.id in (some ids...)
In wich way it can be achived with lamdaj or guava?
With Guava this is done as follows:
final Set<Long> ids = ...; //initialize correctly
List<CustomObject> results = FluentIterable.from(existingValues).filter(new Predicate<CustomObject>() {
#Override
public boolean apply(final CustomObject input) {
return ids.contains(input.getId());
}
}).toList();
With Java 8 you can achieve this with a stream filter:
List<CustomObject> collect = existingValues.stream()
.filter(object -> ids.contains(object.getId()))
.collect(Collectors.toList());
To get familiar with java streams I recommand the offical Oracle Tutorial.
Yes as #wuethrich44 says in Java 8 the solution is:
List<CustomObject> collect = existingValues.stream()
.filter(object -> ids.contains(object.getId()))
.collect(Collectors.toList());
And in the case you have a version older than Java 8:
List<CustomObject> collect = new ArrayList<CustomObject>();
for(CustomObject object: existingValues) {
if(ids.contains(object.getId())) {
collect.add(object);
}
}
And for version older than Java 5:
List<CustomObject> collect = new ArrayList<CustomObject>();
Iterator<CustomObject> iterator = existingValues.iterator();
while(iterator.hasNext()) {
CustomObject object = iterator.next();
if(ids.contains(object.getId())) {
collect.add(object);
}
}
but the version with stream is better: faster in term of execution time, less verbose, and more readable if you are use to it
If you can use my xpresso library you can use list comprehensions with lambda expressions like this:
list<CustomObject> filtered = x.list(x.<CustomObject>yield().forEach(existingValues).when(x.lambdaP("x : f1(f0(x))",x.invoke("getId"),x.in(ids))));

Select distinct values from MongoDB array using Java

I want to get a list of unique values from a List field called categories.
I am using Java and MongoDB. Most of the examples and docs I can see seem to suggest I need to do something like what I have below:
public static List<String> listCategories(String input) {
Datastore ds = Dao.instance().getDatabase();
BasicDBObject dbObject=new BasicDBObject("categories", input);
DBCollection dBCollection = ds.getCollection(Product.class);
List<String> categories = dBCollection.distinct("categories",dbObject);
return categories;
}
However when I test it using this code:
#Test
public void testListCategories(){
List<String> categories = Product.listCategories("S");
Assert.assertTrue(categories.size() > 0);
}
The test fails even though I know there are categories that start with S (have also tried a few others just to be sure).
Is it even possible to do this, if so do you have any pointers?
Thanks
BasicDBObject dbObject=new BasicDBObject();
dbObject.append(categories", input);
Now it will be like a where condition,
DBCollection dBCollection = ds.getCollection(Product.class);
List<String> categories = dBCollection.distinct("categories",dbObject);
The test fails even though I know there are categories that start with S (have also tried a few others just to be sure).
You need to perform a regex match using the $regex operator on the categories field to find distinct categories that start with a particular input.
Your updated code should look like:
BasicDBObject like = new BasicDBObject("$regex",
java.util.regex.Pattern.compile("^"+input,
Pattern.CASE_INSENSITIVE));
BasicDBObject query = new BasicDBObject("categories", like);
List<String> categories = dBCollection.distinct("categories",query);

Map Reduce with mongoDB and Morphia

I am running map reduce in mongoDB with morphia, this is my java code
String map = "function() { emit(this.id,this.cal.charge)}";
String reduce = "function(k, v) {var i, sum = 0;for (i in v) {sum += v[i];}return sum;}";
MapreduceResults<Results> mrRes = ds.mapReduce(MapreduceType.MERGE,ds.createQuery(MyTable.class).field("id").equal(5),map,reduce,null,null,Re.class);
This work fine and put results to 'Re' collection, but how can i get result as objects or list without inserting to a new Collection ?
Thanks
I couldn't commented this because it violates the length limit.
If it is not going to be too much of a fuss, you can do it by using java driver directly without using the morphia interface. just get the mongo object from morphia datastore and use java driver's map reduce command; it is something like this:
DBObject queryObject = new BasicDBObject("id", 5);
DBCollection collection = ds.getCollection(MyTable.class);
MapReduceCommand mrc = new MapReduceCommand(collection, // collection to do map-reduce on
map, // map function
reduce, // reduce function
null, // output collection for the result
MapReduceCommand.OutputType.INLINE, // output result type
queryObject); // query to use in map reduce function
btw morphia has a newer version in github https://github.com/jmkgreen/morphia maybe you wanna check that out too. I saw that the newer version also don't support inline operation on map-reduce.

Categories

Resources