在Spring Data MongoDB中如何仅返回特定字段的查询结果?

29

如何在Spring Data Mongo中选择特定的字段。我尝试了以下方法,但是我得到了从FooString的转换异常。

使用@Query

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

@Query

String findPathByPath(String path);

这里是文档模型

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

  String name, path;
  …
}

你在说什么?MongoDB没有列。 - chrylis -cautiouslyoptimistic-
1
我想从我的模型中仅返回特定字段。在 SQL 中,它相当于 SELECT path FROM foo - richersoon
@Oliver Drotbohm - 有没有办法可以找出这两个记录中不同的那一个? - PAA
7个回答

35

MongoDB仅针对标准查询返回JSON文档。您想要查看的内容可以通过仍然返回List<Foo>来实现。在@Query中使用fields属性将导致仅返回设置为1的字段。

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

通常我们建议为此引入专用的DTO,以便防止部分填充的Foo实例被传递给save(…)

另一个选择是使用聚合框架,但这需要更多的工作。


3
Oliver,为每个选择查询创建DTO并不可行,因为我们运行了大量查询来选择数据子集。在Spring Data JPA中,对于我们不想映射到DTO的情况,会返回List<Object[]> 。类似于此,是否有API可以返回值的MAP而不是映射到DTO? - VimalKumar
谢谢!我们知道仅返回特定字段会更有效率吗?有进行过任何分析吗? - Samuel Dominguez

28
您可以使用

标签。

Query query = new Query();

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

22

您可以使用

public interface PersonRepository extends MongoRepository<Person, String>

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

}

更多关于Spring Data的信息,请参阅文档


如果我想获取所有文档的某些字段,我需要设置值为“{}”,如果我没有设置该值,它将检查方法的名称。但是我没有检查在这种情况下(未设置该值)它是否会处理注释中的字段。 - alvinmeimoun
@Nikhil Kumar K - 有没有办法找出不同的记录? - PAA
@PAA 你能试试查找按照人的名字的去重吗? - Nikhil Kumar K
@@Nikhil Kumar K - 方法 "atleast" 至少需要一个参数。我只是想查找所有 FirstName。 - PAA
基于你的回答中的这部分内容 "fields = {'firstname':1,'lastname':1} ",数字 '1' 代表什么意思?你能解释一下吗? - Amir Azizkhani

9
您可以使用以下查询来获取特定字段。
@Query(fields="{path : 1}")
Foo findPathByPath(String path);

数据库中的记录

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

如果路径(path)为Path3,下面的查询将返回Foo对象。
{
    "name": null,
    "path": "path3"
}

我们需要使用fieldName:1来指定必填字段,如果不需要,则使用0进行指定。

1
我在尝试从集合中的特定对象获取字段值时,发现了这个问题。我的研究显示,Mongo没有提供本地返回对象中特定字段值的方法。(令人失望的是,就像在SQL或JSONPath中一样能够返回特定字段的值似乎是相当基础的要求)。
为了解决这个问题,我使用Java 11中的Spring MongoDB编写了以下方法:
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);
}
getEmbedded调用允许我们获取返回的Bson文档中嵌套字段的值。
要使用该方法,只需像这样调用它:
getFieldValueById("A1234", "field.nestedfield.nestedfield", "collectionName", String.class);

希望这能帮助其他寻找如何做到这一点的人。
顺便提一下,我不确定如何将其扩展为返回对象列表-如果遇到这个问题并解决了它,我会尝试更新此答案。我也不确定这是否比运行Mongo聚合查询更慢-我没有尝试在两种方法之间运行任何性能比较。
编辑2022-09-30:要返回自定义Pojo的列表,似乎必须使用spring-data-mongodb通过聚合查询。另外,基本查询似乎比聚合查询更快,因此在可能的情况下请使用基本查询。

0

0
你可以进行以下操作。
在你的仓库中,有如下方法:
String findPathByPath(String path);

如果文档看起来像这样(下面),并且您只想返回路径
@Document(collection = "foo")
public class Foo  {

  String name;
  String path;
  String type;
  …
}

然后创建一个 Projection 接口,例如:
@Projection(name = "flattenedFoo", types = Foo.class)
public interface FlattenedInvoice {
    String getPath(); // This returns the path value in Foo class
}

您可以使用 getter 方法从 Foo 中获取您感兴趣的字段。
然后在您的 get 请求中,您需要指定 projectionName。例如,使用(@Resource path)。
@RestResource(path = "findByPath", rel = "findByPath")
String findPathByPath(String path);

你可以在GET请求中这样写:
..../findByPath?path=target_path&projection=flattenedFoo
这将返回一个JSON,其中仅包含FlattenedFoo接口中指定的字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接