29

How can we select specific fields in Spring Data Mongo. I tried the following but I got cast exception from Foo to String.

Using @Query

@Query(value="{path : ?0}", fields="{path : 0}")
String findPathByPath(String path);

Non @Query

String findPathByPath(String path);

Here is the document model

@Document(collection = "foo")
public class Foo  {

  String name, path;
  …
}
3
  • What are you talking about? MongoDB doesn't have columns. Commented Aug 20, 2015 at 3:43
  • 1
    I want to return only the specific field from my model. In sql it is equivalent of SELECT path FROM foo Commented Aug 20, 2015 at 4:31
  • @Oliver Drotbohm - Is there any way if we can find out the distinct record out of the two? Commented Apr 4, 2019 at 17:50

7 Answers 7

36

MongoDB only returns JSON documents for standard queries. What you'd like to see can be achieved by still returning a List<Foo>. The fields property in @Query will cause only the fields set to 1 being returned.

@Query(value="{ path : ?0}", fields="{ path : 0 }")
List<Foo> findByPath(String path);

We usually recommend introducing a dedicted DTO for that so that you prevent the partially filled Foo instance from being handed to save(…) in turn.

Another option is using the aggreation framework but that's more involved.

Sign up to request clarification or add additional context in comments.

3 Comments

Oliver, Creating a DTO for every select query is not feasible as we run lot of queries to select sub set of data. Spring Data JPA returns List<Object[]> in cases where we dont want to map to DTO. Similalr to that, Is there any API to return a MAp of values instead of mapping to a DTO?
Thanks! Does we know how much more efficient it is to return only specific fields? Any profiling done on this?
In case you're not aware, there is a native support for this in Spring using projections. More details: docs.spring.io/spring-data/mongodb/reference/repositories/…
28

You can use

Query query = new Query();

query.fields().include("path");

Comments

22

You can use

public interface PersonRepository extends MongoRepository<Person, String>

  @Query(value="{ 'firstname' : ?0 }",fields="{ 'firstname' : 1, 'lastname' : 1}")
  List<Person> findByThePersonsFirstname(String firstname);

}

More information in spring data documentation

5 Comments

If i want to get some fiels of all documents, i need to set value = "{}" , if i didn't set the value, it will check the name of the method. But i didn't check if in this case (not set the value) it will take care of the fields in the annotation
@Nikhil Kumar K - Is there any way if we can findout the distinct records?
@PAA Can you try findDistinctByThePersonsFirstname
@@Nikhil Kumar K - Method atleast expects one parameter in the method. I am simply looking find all FirstName
base on this part of your answer " fields="{ 'firstname' : 1, 'lastname' : 1} ", what mean ' 1 ' number? can you explain about that?
9

You can use below query to get specific fields.

@Query(fields="{path : 1}")
Foo findPathByPath(String path);

Records present in DB

{
    "name" : "name2",
    "path" : "path2"
},
{
    "name" : "name3",
    "path" : "path3"
}

Below query will return Foo object if path=Path3

{
    "name": null,
    "path": "path3"
}

we need to specify required fields with fieldName:1 and if don't require then specify it with 0.

Comments

2

I found this question while trying to get the value of a field from a specific object in my collection. From what my research shows, Mongo doesn't provide a way to natively return just a specific field's value from an object. (Disappointing since it seems pretty basic to be able to return just a specific value from a field like I would do in SQL or JSONPath).

To get around this, I wrote the following method using Spring MongoDB with Java 11:

import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.MongoTemplate; //not used, just showing which type the template is
import java.util.Arrays;
import static java.util.Objects.requireNonNull;

/**
 * Use this method to get a specific field from an object saved in Mongo. The objectId will be
 * the id of the object to fetch, and the fieldValueToReturn will be the field to return.
 *
 * @return the value of the provided field-path converted to the class type provided
 */
public <T> T getFieldValueById(String objectId, String fieldValueToReturn, String collectionName, Class<T> classTypeToReturn) {
    var query = new Query().addCriteria(Criteria.where("_id").is(objectId));
    query.fields().include(fieldValueToReturn);
    var result = mongoTemplate.findOne(query, org.bson.Document.class, collectionName);
    requireNonNull(result, "Did not find any documents with id '" + objectId + "' in collection: " + collectionName);
    return result.getEmbedded(Arrays.asList(fieldValueToReturn.split("\\.")), classTypeToReturn);
}

The getEmbedded call allows us to get the value of the nested field within the returned Bson document.

To use the method, just call it like this:

getFieldValueById("A1234", "field.nestedfield.nestedfield", "collectionName", String.class);

Hopefully this helps out someone else looking on how to do this.


As a side note, I'm not sure how to extend this to return a list of objects - if I get to that dilemma and solve it, I will try to update this answer. I'm also not sure if this is slower than running a Mongo aggregate query - I haven't tried running any performance comparisons between the two methods.

EDIT 2022-09-30: To return a list of a custom Pojo, it looks like you'll have to use an aggregate query via spring-data-mongodb. Also it seems basic queries are faster than aggregate queries, so use basic queries where possible.

Comments

0

You can directly pass your json query with @Query annotation, for example:

@Query("{ 'firstname' : 'john' }")

Here is the link to all json based queries in Spring Data MongoDb - https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongodb.repositories.queries.json-based

Comments

0

You can do the following.

In your repository, you have the method:

String findPathByPath(String path);

If the document looks like this (below), and you want to only return path

@Document(collection = "foo")
public class Foo  {

  String name;
  String path;
  String type;
  …
}

Then create a Projection interface, e.g.

@Projection(name = "flattenedFoo", types = Foo.class)
public interface FlattenedInvoice {
    String getPath(); // This returns the path value in Foo class
}

You can use the getter methods to get the fields from Foo that you are interested in.

Then in your get request, you would have to specify the projectionName. e.g. with (@Resource path)

@RestResource(path = "findByPath", rel = "findByPath")
String findPathByPath(String path);

You could then say (In a get request):

..../findByPath?path=target_path&projection=flattenedFoo

this would then return a json with only the fields specifies in FlattenedFoo interface.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.