MarkLogic xdmp.nodeInsertChild how to insert an array in json object

47 Views Asked by At

I have the following scaffold code with will insert nodes inside an existing object in database. The code assumes that any fields present in xpath sequence is update or it is an insert into the parentNode. This works for simple objects but if you try to insert an array through nodeBuilder it throws an exception on xdmp.insertNodeChild. It does work if the node uses an update statement. Is this a bug or am I missing something

{
"saying": {
"quote": "I'd rather regret the things I've done than regret the things I haven't done", 
"person": "Lucille Ball", 
"born": "Jamestown, New York, USA", 
"dob": "1911-08-05", 
"category": ["fun", "inspirational"], 
   "likes": 3, 
   "foo": "bar", 
   "babson": [1, 2, 3]
  }
}

Here is the code I tries to run you can change babson to babo and will throw an exception. Running with babson as an update works as expected

'use strict';
declareUpdate();
let node = new NodeBuilder();
let nb = node.addNode({"likes": 3,"dob":"1911-08-05","foo":"bar","babson": [1,2,3]}).toNode();

let props = []
for(const [key, value] of Object.entries(nb)) {
  props.push(key)
}
let doc = cts.doc("/sayings/lb_regret.json")

//console.log(`======${xdmp.random()}======`)

for(let prop of props) {
  let propPath = `/saying/${prop}`
  let propSeq = doc.xpath(propPath)
  if(propSeq.toArray().length !== 0) {
    xdmp.nodeReplace(propSeq,nb[prop])
  } else {
    let cnb = new NodeBuilder()
    let child = {}
    child[prop] = nb[prop];
    let childNode = cnb.addNode(child)
    xdmp.nodeInsertChild(doc.xpath('/saying'), childNode.toNode().xpath(`/${prop}`))
  }
}

if I try to insert an array it throws the following error

[javascript] XDMP-ARGTYPE: xdmp.nodeInsertChild(Sequence(xdmp.unpath("fn:doc('/sayings/lb_regret.json')/saying")), Sequence(NumberNode(1), NumberNode(2), NumberNode(3))) -- arg2 is not of type Node

Stack Trace
In undefined on line 24
In xdmp.nodeInsertChild(Sequence(xdmp.unpath("fn:doc('/sayings/lb_regret.json')/saying")), Sequence(NumberNode(1), NumberNode(2), NumberNode(3)))
1

There are 1 best solutions below

1
On BEST ANSWER

The reason you are getting that error is because of a subtle difference of how XPath against a JavaScript array works in MarkLogic.

When you use an XPath like:

/saying/babson

it returns a sequence of items that are in that array, but not the array node itself. That is why the error says "arg2 is not of type Node", because it's actually a sequence of Number nodes.

If you want to select and return the array-node() then you need to use the array-node() and specify the name:

/saying/array-node('babson')

And you can use the more generic node() selector as you iterate over the named properties:

for (let prop of props) {
  let propPath = `/saying/node('${prop}')`
  let propSeq = doc.xpath(propPath)
  xdmp.nodeReplace(propSeq, nb[prop])
}