使用两个字段查询嵌套对象的MongoDB查询。

huangapple go评论97阅读模式
英文:

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 存储库,展示了不同的选项:

  1. 创建自定义查询

在您的情况下,查询应如下所示:

@Query(value = "{ $and: [{'documents.clientId' :  ?0},{'documents.documentId' :  ?1}]}", fields = "{ 'documents' : 1}")
ClientData findDocument(String clientId, String documentId);

请注意,此查询返回 ClientData(包括整个 SignedDocument 列表),因此您仍然需要在之后筛选结果。

*字段参数不是强制的,但如果有许多属性,您可以使用它来指示要检索哪些属性。其他字段为空。

  1. 创建自定义方法
ClientData findByDocuments_ClientIdAndDocuments_DocumentId(String clientId, String documentId);

在这种情况下,Spring 会直接从方法名派生查询。请注意,您仍然需要进行筛选,因为您会检索到 ClientData 对象。

  1. 使用 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:

  1. Creating a custom query

In your case the query would look as follows:

@Query(value = &quot;{ $and: [{&#39;documents.clientId&#39; :  ?0},{&#39;documents.documentId&#39; :  ?1}]}&quot;, fields = &quot;{ &#39;documents&#39; : 1}&quot;)
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.

  1. 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.

  1. 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(&quot;documents&quot;);
MatchOperation match = Aggregation.match(Criteria.where(&quot;documents.clientId&quot;).is(requestedClientId).and(&quot;documents.documentId&quot;).is(requestedDocumentId));
Aggregation aggregation = Aggregation.newAggregation(unwind, match);
AggregationResults&lt;SignedDocumentUnwind&gt; results = mongoTemplate.aggregate(aggregation, &quot;client_data&quot;,
                SignedDocumentUnwind.class);
return results.getMappedResults().stream().map(SignedDocumentUnwind::getDocuments).toList();

The advantage is that there's no need to filter for the requested SignedDocument.

huangapple
  • 本文由 发表于 2023年8月5日 01:32:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76838070.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定