Как запросить mongo с несколькими ссылками на db

#mongodb #spring-mongodb

#mongodb #spring-mongodb

Вопрос:

Допустим, у меня есть следующая структура БД, у меня есть коллекция пользователей

 "users": [
    {
      "_id": "4775222e-8e4f-4f84-8dba-b097291bbd39",
      "surname": "Smith",
      "forename": "John"
    }
  ]
 

У меня есть коллекция job_requests, в которой есть ссылка на коллекцию пользователей в 1 поле, например:

 "job_requests": [
    {
      "_id": "f4bdda3e-0e8d-4e8d-b070-7d01421f5a51",
      "description": "do something",
      "riskManager": {
        "$ref": "users",
        "$id": "4775222e-8e4f-4f84-8dba-b097291bbd39"
      }
    }
  ]
 

И, наконец, у меня есть коллекция заданий, в которой есть ссылка на коллекцию job_requests в 1 поле:

 "jobs": [
    {
      "_id": "someID",
      "description": "do something",
      "jobRequest": {
        "$ref": "job_requests",
        "$id": "f4bdda3e-0e8d-4e8d-b070-7d01421f5a51"
      }
    }
  ]
 

Мне нужен запрос, который вернет все задания по идентификатору пользователя, что означает, что мне нужно найти все job_requests с этим пользователем, а затем все задания с этими job_requests.
Я попробовал с агрегацией mongo на MongoPlayground, и это работает, но только для mongo 4.4.1

 db.jobs.aggregate([
  {
    "$lookup": {
      "from": "job_requests",
      "localField": "jobRequest.$id",
      "foreignField": "_id",
      "as": "jobRequest"
    }
  },
  {
    "$unwind": "$jobRequest"
  },
  {
    "$match": {
      "jobRequest.riskManager.$id": "4775222e-8e4f-4f84-8dba-b097291bbd39"
    }
  }
])
 

И дает мне правильный результат. Проблема в том, что мой сервер 4.2.8, и в этой версии это приводит к ошибке «Имена полей FieldPath могут не начинаться с ‘$'».
Как я могу сделать запрос, чтобы он не прерывался на 4.2.8? Я не могу реструктурировать данные, мне нужно иметь все эти отношения между коллекциями. Я мог бы добавить, что серверная часть поверх этого — spring data mongodb, поэтому я могу использовать эти функции для построения запроса, но я предполагаю, что это сводится к javascript для mongo QL.

Ответ №1:

Как предлагается в этом сообщении в блоге, это можно сделать с помощью оператора $objectToArray, $arrayElemAt и $ addFields.

таким образом, это становится чем-то вроде

 db.jobs.aggregate([
  {
    "$addFields": {
      "jobRequest": {
        "$arrayElemAt": [
          {
            "$objectToArray": "$jobRequest"
          },
          1
        ]
      }
    }
  },
  {
    "$addFields": {
      "jobRequest": "$jobRequest.v"
    }
  },
  {
    "$lookup": {
      "from": "job_requests",
      "localField": "jobRequest",
      "foreignField": "_id",
      "as": "jobRequest"
    }
  },
  {
    "$addFields": {
      "jobRequest": {
        "$arrayElemAt": [
          "$jobRequest",
          0
        ]
      }
    }
  },
  {
    "$unwind": "$jobRequest"
  },
  {
    "$match": {
      "jobRequest.riskManager.$id": "4775222e-8e4f-4f84-8dba-b097291bbd39"
    }
  }
])
 

Избегайте DBRef любой ценой при использовании mongo.