英文:
Monodb query nested object by two fields
问题
我需要通过clientId和documentId从“documents”中获取一个文档。如何检索数据?
架构:
{
"_id": ObjectId('64cd1e1877dd3b45ce2715d4'),
"name": 'string',
"clientId": '79fc89fe-32de-11ee-be56-0242ac120002',
"dateBirth": ISODate('2023-08-04T10:49:30.594Z'),
"addressReg": 'string',
"addressFact": 'string',
"passportSeries": 'string',
"passportNumber": 'string',
"mobilePhone": 'string',
"anotherMobilePhone": 'string',
"email": 'string',
"oneMoreEmail": 'string',
"cardName": 'string',
"currencyName": 'string',
"paymentSystem": 'string',
"tariff": 'string',
"signingDate": ISODate('2023-08-04T10:49:30.594Z'),
"documents": [
{
"clientId": '79fc89fe-32de-11ee-be56-0242ac120002',
"documentId": '64cd160a68f6d71fc5f68098',
"title": 'T_rules.md',
"signed": true
}
],
"_class": 'com.example.mvpmongo.model.ClientData'
}
当我尝试此查询时,尽管clientId和documentId是正确的,但我得到null。
@Query("{ $and: [{'documents' : { $elemMatch: {'documentId': ?1}}},{'clientId': ?0}]}")
SignedDocument findDocument(String clientId, String documentId);
我是Mongo的新手,请您解释一下我做错了什么。
英文:
I need to get a document from "documents" by clientId and documentId. How can I retrieve the data?
Schema:
{
_id: ObjectId('64cd1e1877dd3b45ce2715d4'),
name: 'string',
clientId: '79fc89fe-32de-11ee-be56-0242ac120002',
dateBirth: ISODate('2023-08-04T10:49:30.594Z'),
addressReg: 'string',
addressFact: 'string',
passportSeries: 'string',
passportNumber: 'string',
mobilePhone: 'string',
anotherMobilePhone: 'string',
email: 'string',
oneMoreEmail: 'string',
cardName: 'string',
currencyName: 'string',
paymentSystem: 'string',
tariff: 'string',
signingDate: ISODate('2023-08-04T10:49:30.594Z'),
documents: [
{
clientId: '79fc89fe-32de-11ee-be56-0242ac120002',
documentId: '64cd160a68f6d71fc5f68098',
title: 'T_rules.md',
signed: true
}
],
_class: 'com.example.mvpmongo.model.ClientData'
}
When I try this query I get null, though clientId and documentId are correct.
@Query("{ $and: [{'documents' : { $elemMatch: {'documentId': ?1}}},{'clientId': ?0}]}")
SignedDocument findDocument(String clientId, String documentId);
I'm new to mongo, could you please explain to me what I am doing wrong.
答案1
得分: 0
Here is the translated content:
有多种解决方案可解决您的问题。我创建了一个 GitHub 存储库,展示了不同的选项:
- 创建自定义查询
在您的情况下,查询应如下所示:
@Query(value = "{ $and: [{'documents.clientId' : ?0},{'documents.documentId' : ?1}]}", fields = "{ 'documents' : 1}")
ClientData findDocument(String clientId, String documentId);
请注意,此查询返回 ClientData
(包括整个 SignedDocument
列表),因此您仍然需要在之后筛选结果。
*字段参数不是强制的,但如果有许多属性,您可以使用它来指示要检索哪些属性。其他字段为空。
- 创建自定义方法
ClientData findByDocuments_ClientIdAndDocuments_DocumentId(String clientId, String documentId);
在这种情况下,Spring 会直接从方法名派生查询。请注意,您仍然需要进行筛选,因为您会检索到 ClientData
对象。
- 使用 unwinding
这个方法稍微复杂一些。基本上,您需要创建一个名为 SignedDocumentUnwinded
的单独类,并将查询结果转换为此类。
UnwindOperation unwind = Aggregation.unwind("documents");
MatchOperation match = Aggregation.match(Criteria.where("documents.clientId").is(requestedClientId).and("documents.documentId").is(requestedDocumentId));
Aggregation aggregation = Aggregation.newAggregation(unwind, match);
AggregationResults<SignedDocumentUnwind> results = mongoTemplate.aggregate(aggregation, "client_data",
SignedDocumentUnwind.class);
return results.getMappedResults().stream().map(SignedDocumentUnwind::getDocuments).toList();
优势在于无需再筛选所请求的 SignedDocument
。
英文:
There are multiple solutions to your problem. I created a GitHub repo showing the different options:
- Creating a custom query
In your case the query would look as follows:
@Query(value = "{ $and: [{'documents.clientId' : ?0},{'documents.documentId' : ?1}]}", fields = "{ 'documents' : 1}")
ClientData findDocument(String clientId, String documentId);
Note that this query returns ClientData
(including the entire list of SignedDocument
), so you still need to filter the result afterwards.
*the fields parameter is not mandatory, but in case there are many attributes you can use it to indicate which attributes you want to retrieve. The others are null.
- Creating a custom method
ClientData findByDocuments_ClientIdAndDocuments_DocumentId(String clientId, String documentId);
In this case Spring derives the query from the method name directly.
Note that you still need to do the filtering, since you retrieve the ClientData
object.
- Use unwinding
This one is a bit more complex. Basically, you need to create a separate class SignedDocumentUnwinded
and convert the result of your query to this class.
UnwindOperation unwind = Aggregation.unwind("documents");
MatchOperation match = Aggregation.match(Criteria.where("documents.clientId").is(requestedClientId).and("documents.documentId").is(requestedDocumentId));
Aggregation aggregation = Aggregation.newAggregation(unwind, match);
AggregationResults<SignedDocumentUnwind> results = mongoTemplate.aggregate(aggregation, "client_data",
SignedDocumentUnwind.class);
return results.getMappedResults().stream().map(SignedDocumentUnwind::getDocuments).toList();
The advantage is that there's no need to filter for the requested SignedDocument
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论