Search code examples
arangodbaql

"unnest" aql query result in arangodb


So let's say I have collection Users and Companies. Then I have edge collection named works_in that links user with companies. I am using the following aql query:

FOR user IN Users
   LET companies = (FOR company IN (NEIGHBORS(Users, works_in, user._id, 'outbound', [], {includeData:true}))
       RETURN {company_name: company.name, company_id: company._id})
RETURN {user, companies}

and what I get is:

[
  {
    "user": {
      "_id": "Users/45645",
      "_key": "45645",
      "_rev": "45645",
      "name": "user1",
      "city": "london",
      "age": 23
    },
    "companies": [
        {
          company_name: "company1",
          company_id: "Companies/7897"
        },
        {
          company_name: "company2",
          company_id: "Companies/7878"
        }
    ]
  },
  {
    "user": {
      "_id": "Users/465454",
      "_key": "465454",
      "_rev": "465454",
      "name": "user2",
      "city": "Paris",
      "age": 42
    },
    "companies": [
        {
          company_name: "company1",
          company_id: "Companies/7897"
        },
        {
          company_name: "company3",
          company_id: "Companies/788233"
        }
    ]
  }
]

However I would like to get "users" info not nested inside a "user" but as follows:

[
  {
    "_id": "Users/45645",
    "_key": "45645",
    "_rev": "45645",
    "name": "user1",
    "city": "london",
    "age": 23,
    "companies": [
        {
          company_name: "company1",
          company_id: "Companies/7897"
        },
        {
          company_name: "company2",
          company_id: "Companies/7878"
        }
    ]
  },
  {
    "_id": "Users/465454",
    "_key": "465454",
    "_rev": "465454",
    "name": "user2",
    "city": "Paris",
    "age": 42,
    "companies": [
        {
          company_name: "company1",
          company_id: "Companies/7897"
        },
        {
          company_name: "company3",
          company_id: "Companies/788233"
        }
    ]
  }
]

I know I could make it by kind of hardcoding attributes such as

RETURN {_id: user.id, _key:user._key, companies}

But the problem is that I have lot of attributes to show and moreover users might not have some particular attribute (so then is displayed as "null")

So, does anyone knows how can I "unnest" users properly? Thank you


Solution

  • You can use MERGE for that. Let me demonstrate this using a return statement:

    db._query(`RETURN MERGE({
          "_id": "Users/465454", "_key": "465454",
          "_rev": "465454",      "name": "user2",
          "city": "Paris",       "age": 42
        }, {"companies": [
            {
              company_name: "company1",
              company_id: "Companies/7897"
            },
            {
              company_name: "company3",
              company_id: "Companies/788233"
            }
        ]})`
    ).toArray() =>
    [ 
      { 
        "_id" : "Users/465454", 
        "_key" : "465454", 
        "_rev" : "465454", 
        "age" : 42, 
        "city" : "Paris", 
        "companies" : [ 
          { 
            "company_id" : "Companies/7897", 
            "company_name" : "company1" 
          }, 
          { 
            "company_id" : "Companies/788233", 
            "company_name" : "company3" 
          } 
        ], 
        "name" : "user2" 
      } 
    ]
    

    Since companies gives you a list, you need to wrap it into an object so MERGE can do its work:

    FOR user IN Users
      LET companiesList = (FOR company IN
                               (NEIGHBORS(Users, works_in, user._id, 'outbound', [],
                                         {includeData:true}))
      RETURN MERGE(user, {companies: companiesList})