Issue
I'm working on spring-boot-data-mongoDB. I have some issues querying a nested document that has a list of a specific object.
Mock class
@Document
public class Mock {
@Id
private String id;
@Indexed(unique = true)
private String name;
private List<Request> requests;
}
Request class
@Document
public class Request {
@Id
private String id;
private int status;
private String method;
private String endPoint;
private Map<String, Object> response;
private Map<String, Object> body;
private Map<String, String> params;
}
Example JSON
[
{
_id: '53fc6dde-7a534-4b37-a57e-t0bd62f50046',
name: 'mock1',
requests: [
{
status: 200,
method: 'GET',
endPoint: 'status',
response: {},
body: {},
params: {}
}
],
_class: 'com.example.mockserverspring.models.Mock'
},
{
_id: '73fc6dde-7a5b-4b37-a57e-d0bd62f50046',
name: 'tester',
requests: [
{
_id: '802220ea-a1c7-484d-af1b-86e29b540179',
status: 200,
method: 'GET',
endPoint: 'api',
response: {
data: 'GET'
},
body: {
body: 'body'
},
params: {
params: 'params'
}
},
{
_id: 'ff8673d7-01a9-4d6f-a42e-0214a56b227b',
status: 200,
method: 'GET',
endPoint: 'data',
response: {},
body: {
data: 'data'
},
params: {
value: '10'
}
},
{
_id: '7fd5a860-b415-43b0-8115-1c8e1b95c3ec',
status: 200,
method: 'GET',
endPoint: 'status',
response: {},
body: {},
params: {}
}
],
_class: 'com.example.mockserverspring.models.Mock'
}
]
Desired query output : pass in the endPoint, mockName, body, params, and method
- Get the mock object of the mockName from the db.
- Match endPoint, body, params, method inside the Requests List of the returned mock.
- Return the response field from the request that is found matching all the above criteria.
From the above example json :
- Passed in values : mockName : tester , method : GET , endPoint : api , body: {body: 'body' }, params: { params: 'params' }
- This should return : response: { data: 'GET' }
- It should return if and only if all these criteria matches.
Any queries please let me know.
Solution
To perform this search the best is to use a mongoDB aggregation, inside this aggregation we will be able to execute operations step by step.
As you want to query only 1 subdocument within an array, the first operation we must perform is a $unwind of that array. This will separate each subdocument and we can perform our search.
{
"$unwind": "$requests"
}
Now we will introduce the search parameters in $match. We will be able to use as many as we want.
{
"$match": {
"name": "tester",
"requests.method": "GET",
"requests.endPoint": "api",
"requests.body": {
body: "body"
},
"requests.params": {
params: "params"
}
}
}
Finally as we only want the information of a specific field we will use $replaceRoot to format our output.
{
"$replaceRoot": {
"newRoot": "$requests.response"
}
}
Answered By - Rubén Vega