Search code examples
mongodbspring-bootmongodb-queryspring-dataspring-data-mongodb

Spring-boot data mongoDB query nested list


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"
        }
      }
    

    Playground