6

I want to remove an attribute from a document in ArangoDB.

I thought the correct method for this was with the function UNSET(doc, attributeName1, ..., attributeNameN). However, with this alone, nothing is changed in the database.

Example:

let target_key = "42"

FOR doc IN myCollection
    FILTER doc._key == target_key
    RETURN UNSET(doc, "myAttribute")

The example returns the original document without the attribute myAttribute, but the new version is not saved to the database, so it seems this is only a projected copy.

Thomas Fauskanger
  • 2,536
  • 1
  • 27
  • 42

2 Answers2

6

The simple answer to this is to combine UNSET with the REPLACE function.

UNSET works on attributes in a single document, and REPLACE works on entire documents in a collection.

let target_key = "42"

FOR doc IN myCollection
    FILTER doc._key == target_key
    REPLACE UNSET(doc, "myAttribute") IN myCollection
    RETURN NEW

This example returns the new document where myAttribute is removed with UNSET that is saved to the collection with REPLACE.

The NEW and OLD keywords can be used as with UPDATE and UPSERT.

I figured this out after I read this issue. I felt this was a too simple task to get stuck on, but I hope this is of use to people after me.

Thomas Fauskanger
  • 2,536
  • 1
  • 27
  • 42
  • 2
    *New* in *Return New* was not recognized, I removed the Return statement and worked just fine. Thanks for saving couple hours of my life. – dvdmn May 12 '19 at 17:25
5

Alternatively, you can set the attribute you want to remove to null and use the keepNull option:

LET target_key = "42"

FOR doc IN myCollection
    FILTER doc._key == target_key
    UPDATE doc WITH { myAttribute: null } IN myCollection
    OPTIONS { keepNull: false }
    RETURN NEW

Attributes with an explicit null value in the document are kept. Only the attributes specified after WITH are touched.

Note: if you explain the query, you will see nullMeansRemove: true under Write query options instead of keepNull: false.

CodeManX
  • 11,159
  • 5
  • 49
  • 70
  • Hei, thanks for the input, I wasn't aware of this way. How does the `OPTIONS { keepNull: false }` treat other attributes with `null` in the document? Let's assume I want to remove an attribute but want to keep other attributes even if they are `null`. Another question is perhaps: what is the (dis)advantages of having no `null`-values? – Thomas Fauskanger Aug 31 '17 at 13:30
  • 1
    As I mentioned, other attributes will remain unchanged, even if they are *null*. Only `myAttribute` will be removed by above query, because it is the only attribute provided: `WITH { myAttribute: null }`. In general, you may or may not store null values in your documents, it depends on what you need to express. In most cases, I assume you could simply remove an attribute if it is unused. If you need a distinction between a value being not available versus actually empty, it is legitimate to store a null value in the latter case. – CodeManX Aug 31 '17 at 13:40
  • Excellent. Thanks, I see now that you explicitly mentioned it. Which method do you think is better? Or, which answer do you think I should mark as "accepted answer"? – Thomas Fauskanger Aug 31 '17 at 13:43
  • 1
    It doesn't really make a difference, a new document revision is written either way. `REPLACE` seems a bit more succinct. But if the attributes you want to remove are nested deeper, then `UPDATE MERGE_RECURSIVE(doc, { a: { b: { c: { targetKey: null } } } }) IN myCollection OPTIONS { keepNull: false }` is the way to go. I tried the same with `REPLACE`, but it doesn't support *keepNull*. – CodeManX Dec 09 '17 at 18:46