FQL v4 will be decommissioned on June 30, 2025. Ensure that you complete your migration from FQL v4 to FQL v10 by that date.

For more details, review the migration guide. Contact support@fauna.com with any questions.

Merge

This reference topic applies to FQL v4. Go to this page for the latest FQL v10 reference topics.

Merge( object1, object2, [customResolver] )
merge( object1, object2, [customResolver] )
Merge( object1, object2, [customResolver] )
Merge( object1, object2, [customResolver] )
Merge( object1, object2, [customResolver] )

Description

The Merge function combines two or more objects into one, by performing a shallow merge of the fields and values from both objects into a new object.

The merge starts with a copy of object1 — called result — and then merges object2 into result, evaluating each top-level field in turn. If object2 is an array of objects to merge, each object within object2 is merged into result in turn.

During the merge, each top-level field of the object to be merged into result is processed by a resolver function, which determines which value to use in result when there is a common field. The default resolver always decides to use the value from the object to be merged, overriding the value in result.

You can provide an optional customResolver function that overrides the default resolver, and is used to determine which value to use.

When the resolver returns a null value, Merge deletes that field in result.

Parameters

Parameter Type Definition and Requirements

object1

Object

The first object to merge with the second object.

object2

Object or Array of Objects.

The second object, or array of objects, to merge with the first object. If an array of objects is provided, each object in the array is merged with object1 in turn.

customResolver

Optional - A lambda function that replaces the default resolver and decides which value to use during the merge.

The customResolver function has the signature:

(field, value1, value2) ⇒ newValue

where field is the name of the field that exists in both object1 and object2, and value1 and value2 are the respective values for that field.

If customResolver returns a null, Merge deletes field from the result.

Returns

An object that is the result of merging object1 with object2 (and any additional objects that you may have provided).

Examples

  1. The following query demonstrates a merge of two objects where there is no key conflict:

    client.query(
      q.Merge(
        { a: 'Apple', b: 'Banana' },
        { x: 'width', y: 'height' },
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    { a: 'Apple', b: 'Banana', x: 'width', y: 'height' }
    result = client.query(
      q.merge(
        {"a": "Apple", "b": "Banana"},
        {"x": "width", "y": "height"}
      )
    )
    print(result)
    {'a': 'Apple', 'b': 'Banana', 'x': 'width', 'y': 'height'}
    result, err := client.Query(
    	f.Merge(
    		f.Obj{"a": "Apple", "b": "Banana"},
    		f.Obj{"x": "width", "y": "height"},
    	))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[a:Apple b:Banana x:width y:height]
    try
    {
        Value result = await client.Query(
            Merge(
                Obj("a", "Apple", "b", "Banana"),
                Obj("x", "width", "y", "height")
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(a: StringV(Apple),b: StringV(Banana),x: StringV(width),y: StringV(height))
    Merge(
      { a: 'Apple', b: 'Banana' },
      { x: 'width', y: 'height' },
    )
    { a: 'Apple', b: 'Banana', x: 'width', y: 'height' }
    Query metrics:
    •    bytesIn:  92

    •   bytesOut:  64

    • computeOps:   1

    •    readOps:   0

    •   writeOps:   0

    •  readBytes:   0

    • writeBytes:   0

    •  queryTime: 5ms

    •    retries:   0

  2. The following query demonstrates a merge when there is a key conflict and no resolver function has been provided:

    client.query(
      q.Merge(
        { f: 'First' },
        { f: 'Fauna' },
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    { f: 'Fauna' }
    result = client.query(
      q.merge(
        {"f": "First"},
        {"f": "Fauna"}
      )
    )
    print(result)
    {'f': 'Fauna'}
    result, err := client.Query(
    	f.Merge(
    		f.Obj{"f": "First"},
    		f.Obj{"f": "Fauna"},
    	))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[f:Fauna]
    try
    {
        Value result = await client.Query(
            Merge(
                Obj("f", "First"),
                Obj("f", "Fauna")
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(f: StringV(Fauna))
    Merge(
      { f: 'First' },
      { f: 'Fauna' },
    )
    { f: 'Fauna' }
    Query metrics:
    •    bytesIn:  66

    •   bytesOut:  26

    • computeOps:   1

    •    readOps:   0

    •   writeOps:   0

    •  readBytes:   0

    • writeBytes:   0

    •  queryTime: 6ms

    •    retries:   0

  3. The following query demonstrates that the default resolver performs a shallow merge:

    client.query(
      q.Merge(
        {
          data: {
            name: 'First',
            unique: 'one',
          },
        },
        {
          data: {
            name: 'Fauna',
            extra: 'two',
          },
        },
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    { data: { name: 'Fauna', extra: 'two' } }
    result = client.query(
      q.merge(
        {
          "data": {
            "name": "First",
            "unique": "one",
          }
        },
        {
          "data": {
            "name": "Fauna",
            "extra": "two",
          }
        }
      )
    )
    print(result)
    {'data': {'name': 'Fauna', 'extra': 'two'}}
    result, err := client.Query(
    	f.Merge(
    		f.Obj{
    			"data": f.Obj{
    				"name": "First",
    				"unique": "one",
    			},
    		},
    		f.Obj{
    			"data": f.Obj{
    				"name": "Fauna",
    				"extra": "two",
    			},
    		},
    	))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[data:map[extra:two name:Fauna]]
    try
    {
        Value result = await client.Query(
            Merge(
                Obj(
                    "data", Obj(
                        "name", "First",
                        "unique", "one"
                    )
                ),
                Obj(
                    "data", Obj(
                        "name", "Fauna",
                        "extra", "two"
                    )
                )
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(data: ObjectV(name: StringV(Fauna),extra: StringV(two)))
    Merge(
      {
        data: {
          name: 'First',
          unique: 'one',
        },
      },
      {
        data: {
          name: 'Fauna',
          extra: 'two',
        },
      },
    )
    { data: { name: 'Fauna', extra: 'two' } }
    Query metrics:
    •    bytesIn: 141

    •   bytesOut:  52

    • computeOps:   1

    •    readOps:   0

    •   writeOps:   0

    •  readBytes:   0

    • writeBytes:   0

    •  queryTime: 2ms

    •    retries:   0

    This happens because only the data field is evaluated, since it is the only top-level field in each object to be merged, and the default resolver simply uses the value for data in object2 for the result.

  4. The following query demonstrates a merge when there is a key conflict and a custom resolver function has been provided:

    client.query(
      q.Merge(
        { c: 'Compare', d: 'Difference' },
        { c: 'Contrast', d: 'Delta' },
        q.Lambda(
          ['key', 'a', 'b'],
          q.If(
            q.Equals(q.Var('key'), 'c'),
            q.Var('a'),
            q.Var('b'),
          )
        )
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    { c: 'Compare', d: 'Delta' }
    result = client.query(
      q.merge(
        {"c": "Compare", "d": "Difference"},
        {"c": "Contrast", "d": "Delta"},
        q.lambda_(
          ["key", "a", "b"],
          q.if_(
            q.equals(q.var("key"), "c"),
            q.var("a"),
            q.var("b")
          )
        )
      )
    )
    print(result)
    {'c': 'Compare', 'd': 'Delta'}
    result, err := client.Query(
    	f.Merge(
    		f.Obj{"c": "Compare", "d": "Difference"},
    		f.Obj{"c": "Contrast", "d": "Delta"},
    		f.ConflictResolver(
    			f.Lambda(
    				f.Arr{"key", "a", "b"},
    				f.If(
    					f.Equals(f.Var("key"), "c"),
    					f.Var("a"),
    					f.Var("b"),
    				)))))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[c:Compare d:Delta]
    try
    {
        Value result = await client.Query(
            Merge(
                Obj("c", "Compare", "d", "Difference"),
                Obj("c", "Contrast", "d", "Delta"),
                Lambda(
                    Arr("key", "a", "b"),
                    If(
                        EqualsFn(Var("key"), "c"),
                        Var("a"),
                        Var("b")
                    )
                )
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(c: StringV(Compare),d: StringV(Delta))
    Merge(
      { c: 'Compare', d: 'Difference' },
      { c: 'Contrast', d: 'Delta' },
      Lambda(
        ['key', 'a', 'b'],
        If(
          Equals(Var('key'), 'c'),
          Var('a'),
          Var('b'),
        )
      )
    )
    { c: 'Compare', d: 'Delta' }
    Query metrics:
    •    bytesIn: 219

    •   bytesOut:  40

    • computeOps:   1

    •    readOps:   0

    •   writeOps:   0

    •  readBytes:   0

    • writeBytes:   0

    •  queryTime: 6ms

    •    retries:   0

  5. The following query demonstrates a merge when an array of objects is provided:

    client.query(
      q.Merge(
        { c: 'Compare', d: 'Difference' },
        [
          { c: 'Contrast', d: 'Delta' },
          { a: 'Apple', b: 'Banana', t: 'Tomato' },
          { c: 'Correlate', t: 'turkey' },
          { d: 'disparity' },
        ],
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    {
      t: 'turkey',
      a: 'Apple',
      b: 'Banana',
      c: 'Correlate',
      d: 'disparity'
    }
    result = client.query(
      q.merge(
        {"c": "Compare", "d": "Difference"},
        [
          {"c": "Contrast", "d": "Delta"},
          {"a": "Apple", "b": "Banana", "t": "Tomato"},
          {"c": "Correlate", "t": "turkey"},
          {"d": "disparity"}
        ]
      )
    )
    print(result)
    {'t': 'turkey', 'a': 'Apple', 'b': 'Banana', 'c': 'Correlate', 'd': 'disparity'}
    result, err := client.Query(
    	f.Merge(
    		f.Obj{"c": "Compare", "d": "Difference"},
    		f.Arr{
    			f.Obj{"c": "Contrast", "d": "Delta"},
    			f.Obj{"a": "Apple", "b": "Banana", "t": "Tomato"},
    			f.Obj{"c": "Correlate", "t": "turkey"},
    			f.Obj{"d": "disparity"},
    		}))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[a:Apple b:Banana c:Correlate d:disparity t:turkey]
    try
    {
        Value result = await client.Query(
            Merge(
                Obj("c", "Compare", "d", "Difference"),
                Arr(
                    Obj("c", "Contrast", "d", "Delta"),
                    Obj("a", "Apple", "b", "Banana", "t", "Tomato"),
                    Obj("c", "Correlate", "t", "turkey"),
                    Obj("d", "disparity")
                )
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(t: StringV(turkey),a: StringV(Apple),b: StringV(Banana),c: StringV(Correlate),d: StringV(disparity))
    Merge(
      { c: 'Compare', d: 'Difference' },
      [
        { c: 'Contrast', d: 'Delta' },
        { a: 'Apple', b: 'Banana', t: 'Tomato' },
        { c: 'Correlate', t: 'turkey' },
        { d: 'disparity' },
      ],
    )
    {
      t: 'turkey',
      a: 'Apple',
      b: 'Banana',
      c: 'Correlate',
      d: 'disparity'
    }
    Query metrics:
    •    bytesIn: 224

    •   bytesOut:  84

    • computeOps:   1

    •    readOps:   0

    •   writeOps:   0

    •  readBytes:   0

    • writeBytes:   0

    •  queryTime: 5ms

    •    retries:   0

  6. The following query demonstrates a merge with a document:

    client.query(
      q.Merge(
        q.Get(q.Ref(q.Collection('Letters'), 122)),
        { x: 10 },
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    { ref: Ref(Collection("Letters"), "122"),
      ts: 1566580631370000,
      data: { letter: 'V', extra: '22nd' },
      x: 10 }
    result = client.query(
      q.merge(
        q.get(q.ref(q.collection("Letters"), 122)),
        {"x": 10}
      )
    )
    print(result)
    {'ref': Ref(id=122, collection=Ref(id=Letters, collection=Ref(id=collections))), 'ts': 1566580631370000, 'data': {'letter': 'V', 'extra': '22nd'}, 'x': 10}
    result, err := client.Query(
    	f.Merge(
    		f.Get(f.Ref(f.Collection("Letters"), 122)),
    		f.Obj{"x": 10},
    	))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[data:map[extra:22nd letter:V] ref:{122 0xc00013a2a0 0xc00013a2a0 <nil>} ts:1603747233950000 x:10]
    try
    {
        Value result = await client.Query(
            Merge(
                Get(Ref(Collection("Letters"), 122)),
                Obj("x", 10)
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(ref: RefV(id = "122", collection = RefV(id = "Letters", collection = RefV(id = "collections"))),ts: LongV(1603756505540000),data: ObjectV(letter: StringV(V),extra: StringV(22nd)),x: LongV(10))
    Merge(
      Get(Ref(Collection('Letters'), 122)),
      { x: 10 },
    )
    {
      ref: Ref(Collection("Letters"), "122"),
      ts: 1624310468410000,
      data: { letter: 'V', extra: '22nd' },
      x: 10
    }
    Query metrics:
    •    bytesIn:  86

    •   bytesOut: 190

    • computeOps:   1

    •    readOps:   1

    •   writeOps:   0

    •  readBytes:  70

    • writeBytes:   0

    •  queryTime: 6ms

    •    retries:   0

  7. The following query demonstrates a merge with the data field of a document:

    client.query(
      q.Merge(
        q.Select('data', q.Get(q.Ref(q.Collection('Letters'), 122))),
        { x: 10 },
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    { letter: 'V', extra: '22nd', x: 10 }
    result = client.query(
      q.merge(
        q.select("data", q.get(q.ref(q.collection("Letters"), 122))),
        {"x": 10}
      )
    )
    print(result)
    {'letter': 'V', 'extra': '22nd', 'x': 10}
    result, err := client.Query(
    	f.Merge(
    		f.Select("data", f.Get(f.Ref(f.Collection("Letters"), 122))),
    		f.Obj{"x": 10},
    	))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[extra:22nd letter:V x:10]
    try
    {
        Value result = await client.Query(
            Merge(
                Select("data", Get(Ref(Collection("Letters"), 122))),
                Obj("x", 10)
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(letter: StringV(V),extra: StringV(22nd),x: LongV(10))
    Merge(
      Select('data', Get(Ref(Collection('Letters'), 122))),
      { x: 10 },
    )
    { letter: 'V', extra: '22nd', x: 10 }
    Query metrics:
    •    bytesIn: 111

    •   bytesOut:  49

    • computeOps:   1

    •    readOps:   1

    •   writeOps:   0

    •  readBytes:  70

    • writeBytes:   0

    •  queryTime: 9ms

    •    retries:   0

  8. The following query demonstrates a merge situation that provides no benefit:

    client.query(
      q.Merge(
        { },
        { foo: 'bar' },
        q.Lambda(
          ['key', 'a', 'b'],
          q.Var('a')
        )
      )
    )
    .then((ret) => console.log(ret))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    {}
    result = client.query(
      q.merge(
        {},
        {"foo": "bar"},
        q.lambda_(
          ["key", "a", "b"],
          q.var("a")
        )
      )
    )
    print(result)
    {}
    result, err := client.Query(
    	f.Merge(
    		f.Obj{},
    		f.Obj{"foo": "bar"},
    		f.ConflictResolver(
    			f.Lambda(
    				f.Arr{"key", "a", "b"},
    				f.Var("a")))))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[]
    try
    {
        Value result = await client.Query(
            Merge(
                Obj(),
                Obj("foo", "bar"),
                Lambda(
                    Arr("key", "a", "b"),
                    Var("a")
                )
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV()
    Merge(
      { },
      { foo: 'bar' },
      Lambda(
        ['key', 'a', 'b'],
        Var('a')
      )
    )
    {}
    Query metrics:
    •    bytesIn: 110

    •   bytesOut:  15

    • computeOps:   1

    •    readOps:   0

    •   writeOps:   0

    •  readBytes:   0

    • writeBytes:   0

    •  queryTime: 2ms

    •    retries:   0

    The customResolver always chooses the value from object1. Since there are no fields in object1, the value returned from customResolver is always null. The null return value means that all of the fields in object2 are removed from object1, which results in an empty object.

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!