23

Has anyone tried incorporating distinct in their query using Spring Data for Mongo. If you have an example can you please post it. Where and how should I include the distinct flag?

Link to the Spring Data Mongo example -- Example 4.4. Query creation from method names

// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
java_dude
  • 4,038
  • 9
  • 36
  • 61

8 Answers8

30

After a little poking around, I have come up with the following solution, which is OK and works, but can probably be improved upon. I am still pretty new to Spring, so if you have a better idea, then please do let me know.

Anyway, here it is:

First off, we use the @Autowired annotation to bring in the base MongoTemplate from spring-data-mongodb

@Autowired
MongoTemplate mongoTemplate;

Once we have that, we can use it to make some queries. Note that this is the slightly smelly part because you have to tell Spring what the return type is and it doesn’t really like that…

// Get the distinct stuff from MongoDB
List<String> coll = mongoTemplate.getCollection("mycollection").distinct("myfield");

In the above code you will notice that I have defined a List type variable called coll that uses the @Autowired MongoTemplate variable to get a collection and then a field using distinct. This is analogous to db.whatever.distinct("term") on the Mongo shell.

Walery Strauch
  • 6,792
  • 8
  • 50
  • 57
paulscott56
  • 496
  • 4
  • 7
  • 1
    Thats interesting. Will give it a try. – java_dude Nov 06 '13 at 07:36
  • Thanks, it worked well for me! We just have to keep in mind that it has a limitation in result size, check their docs: https://docs.mongodb.com/manual/reference/method/db.collection.distinct/#definition – dk7 Apr 18 '18 at 09:33
  • @paulscott56 Is there anyway I can use a Query before I get distinct values for a field? Like, I want to get distinct values only when `x=1`, how can provide that criteria? – Shubham A. Jul 16 '18 at 14:00
12

My environment: spring-data-mongodb 2.0.5,jdk1.8,

Here is my code sample:

import com.mongodb.client.DistinctIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;


public List<String> queryAllCategory() {
    List<String> categoryList = new ArrayList<>();
    MongoCollection mongoCollection = mongoTemplate.getCollection("lexicon");
    DistinctIterable distinctIterable = mongoCollection.distinct("category",String.class);
    MongoCursor cursor = distinctIterable.iterator();
    while (cursor.hasNext()) {
        String category = (String)cursor.next();
        categoryList.add(category);
    }
    return categoryList;
}

about distinct method,please read: http://mongodb.github.io/mongo-java-driver/3.7/javadoc/com/mongodb/client/MongoCollection.html#distinct-java.lang.String-java.lang.Class-

iengchen
  • 341
  • 4
  • 9
  • Could you please guide here: https://stackoverflow.com/questions/55535331/spring-data-mongo-issue-with-distinct-collection ? – PAA Apr 05 '19 at 12:36
  • This worked for me, remember to have the 2nd argument be the type of the property you are extracting. I thought at first List.class would be a working solution - but that does not work. – alext Aug 16 '19 at 08:48
9

Lot has changed since this question was posted. Answering my own question as this question keeps popping up.

Support is there since 3.0 and higher

public DistinctIterable<String> getUniqueTask() {
    return mongoTemplate.getCollection(TABLE).distinct("FIELD", String.class);
}

Side Note: You can even add filters/regex to this query. Read docs. If you cannot find, ping, will post the answer.

java_dude
  • 4,038
  • 9
  • 36
  • 61
7

Way to Retrieve strongly typed distinct values using Mongo Template:

mongoTemplate.query(Person.class)  
.distinct("lastname")       
.as(String.class)           
.all(); 

Here is the official documentation - https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo-template.query.distinct

akshitmahajan
  • 668
  • 1
  • 9
  • 17
5

Currently MongoDB does not support to retrieve documents in a distinct way. It only supports returning distinct field values using the distinct command.

As it is apparently the latter you're looking for, the bad news is, we currently don't support any projections in derived queries. For progress on this, please follow the related JIRA ticket.

Oliver Drotbohm
  • 80,157
  • 18
  • 225
  • 211
  • 1
    Oliver I appreciate you responding. Really appreciate what you are doing. I am not looking for distinct document but distinct field values. Though `MongoDB query` supports distinct I could not find `Spring Data` supporting this feature in its `query`. Simple scenario I can think of - Lets say there are X users from different countries. Can I have distinct countries listed for all the users. BTW I am using `@DBRef` if thats could be considered as `Join`, but thats off topic and yes your are right individual documents are distinct. – java_dude Oct 08 '13 at 04:12
  • 1
    I was able to solve the issue by using `java.util.Set`. Would be nice if I could set the distinct requirement in the `Query`. – java_dude Oct 08 '13 at 04:22
  • @Oliver Drotbohm - Do we've distinct feature for Query now ? – PAA Apr 04 '19 at 17:54
  • @java_dude - Could you please post your answer ? How did you solved this? – PAA Apr 05 '19 at 12:32
  • @PAA I have posted my solution. HTH – java_dude Apr 09 '19 at 16:50
3

You can see the differences of the usage of distinct between Spring Data JPA and Spring Data MongoDB here:

@Before
public void setUp() {

    this.dave = customers.save(new Customer("Dave", "Matthews"));
    this.carter2 = customers.save(new Customer("Carter", "Z"));
    this.carter = customers.save(new Customer("Carter", "Beauford"));
}

@Test
public void distinctProjectsEntityIntoInterface() {

    Collection<CustomerProjection> result = customers.findAllProjectedDistinctBy();

    assertThat(result, hasSize(2));
}

distinct in spring data jpa

@Before
public void setUp() {

    customers.deleteAll();

    this.dave = customers.save(new Customer("Dave", "Matthews"));
    this.carter2 = customers.save(new Customer("Carter", "Z"));
    this.carter = customers.save(new Customer("Carter", "Beauford"));
}

@Test
public void distinctProjectsEntityIntoInterface() {

    Collection<CustomerProjection> result = customers.findAllProjectedDistinctBy();

    assertThat(result, hasSize(3));
}

distinct in spring data mongodb

where

interface CustomerProjection {

    String getFirstname();
} 
vmartin
  • 493
  • 4
  • 15
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/15712167) – HDJEMAI Apr 02 '17 at 01:21
  • @H. DJEMAI Thanks for the review, I've changed it. – vmartin Apr 03 '17 at 08:35
0

You can do it with the help of MongoOperations -

Query query = new Query(where("field").in(requestIds));
List<String> result =  mongoOperations.findDistinct(query, "fieldName",                                                                              "collectionName",                                                                    String.class);

With MongoTemplates -

mongoTemplate.getCollection("collectionName").distinct("filedName", requestIds);
Arun Kumar
  • 91
  • 1
  • 7
0

If you want a list of distinct values in a list of Strings,

List<String> emailIds = mongoTemplate.query(Person.class).distinct("email").as(String.class).all();
Nagaraja JB
  • 729
  • 8
  • 18