What I am trying to do is replace the content field within the query’s context such that the SELECT and WHERE clauses go against the replaced object.
The use case for this would be filtering content such that both fruits, materials, ... only contain objects having a specific shop_id value. Then the idea is that WHERE clauses for the content field only work for the shop-specific objects.
This is because we are generating filters dynamically so that the user can filter the data freely, but we want to limit their queries on a per-shop basis. And there is no practical way for us to inject the shop_id match clause onto the user-provided filter - hence the need to first have a shop-limited content and then apply the filter on it.
If user want to specific show id you can write query like this.
SELECT d.*, { "fruits": ARRAY f FOR f IN d.content.friuts WHEN f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd" END,
"materials": ARRAY m FOR m IN d.content.friuts WHEN m.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd" END} AS content
FROM default AS d
WHERE ANY f IN d.content.friuts SATISFIES f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd" END
OR ANY m IN d.contet.materials SATISFIES m.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd" END
OR
SELECT u.*
FROM default AS d
UNNEST ARRAY_CONCAT((SELECT RAW f FROM d.content.friuts AS f WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd"),
(SELECT RAW m FROM d.content.materials AS m WHERE m.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")) AS u
OR
SELECT u.*
FROM default AS d
UNNEST (ARRAY v FOR v WITHIN d.content WHEN v.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd" END) AS u
If you still have question post the materials portion of the document and post the expected output.
SELECT content
FROM bucket AS b
LET content = {
"friuts" : (SELECT RAW f FROM b.content.friuts AS f WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd"),
"materials" : (SELECT RAW m FROM b.content.materials AS m WHERE m.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")
}
)
WHERE ANY material IN content.materials SATISFIES
material.number > 40
END
SELECT content
FROM `bucket` AS b
LET content = (OBJECT o.name:o.val
FOR o IN (ARRAY {v.name ,
"val": (SELECT RAW f
FROM b.content.[v.name] AS f
WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")
}
FOR v IN OBJECT_PAIRS(b.content) END)
WHEN o.val != []
END)
WHERE ANY material IN content.materials SATISFIES
material.`number` > 40
END
You can’t override source object.
The above query has once source of document b
Then let clause did content = …
Left side become second source, right side can uses first source.
Rest of the query has two sources b , content.
If you want use derived source use content. If you want original one use b.content
SELECT newcontnent
FROM `bucket` AS b
LET newcontent = (OBJECT o.name:o.val
FOR o IN (ARRAY {v.name ,
"val": (SELECT RAW f
FROM b.content.[v.name] AS f
WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")
}
FOR v IN OBJECT_PAIRS(b.content) END)
WHEN o.val != []
END)
WHERE ANY material IN newcontent.materials SATISFIES
material.`number` > 40
END
SELECT b.*, newcontnent AS content
FROM `bucket` AS b
LET newcontent = (OBJECT o.name:o.val
FOR o IN (ARRAY {v.name ,
"val": (SELECT RAW f
FROM b.content.[v.name] AS f
WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")
}
FOR v IN OBJECT_PAIRS(b.content) END)
WHEN o.val != []
END)
WHERE ANY material IN newcontent.materials SATISFIES
material.`number` > 40
END
Above query select all fields of b and then override content with specific to shop_id content
CASE cade let only there is next release and you can’t reuse or override variable in the scope again.
Use subquery and project so that original content will be replaced.
SELECT ..
FROM (SELECT b.*, (OBJECT o.name:o.val
FOR o IN (ARRAY {v.name ,
"val": (SELECT RAW f
FROM b.content.[v.name] AS f
WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")
}
FOR v IN OBJECT_PAIRS(b.content)
END)
WHEN o.val != []
END)
FROM `bucket` AS b
) AS b
WHERE ANY material IN b.content.materials SATISFIES
material.`number` > 40
END;
Not sure what is name ?? ANY clause already filters out if materials is empty.
If you want you can try this also
SELECT ..
FROM (SELECT b.*, newcontect AS content
FROM `bucket` AS b
LET newcontect = (OBJECT o.name:o.val
FOR o IN (ARRAY {v.name ,
"val": (SELECT RAW f
FROM b.content.[v.name] AS f
WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")
}
FOR v IN OBJECT_PAIRS(b.content)
END)
WHEN o.val != []
END)
WHERE newcontect.materials IS NOT NULL
) AS b
WHERE ANY material IN b.content.materials SATISFIES
material.`number` > 40
END;
INSERT INTO `bucket` VALUES ("k01", { "id": "1bd5a092-836c-4b6b-a355-e39f9647d397", "content": { "fruits": [ { "text": "apples", "shop_id": "0a04c659-682e-4049-b710-f47ebbd884cd" }, { "text": "bananas", "shop_id": "d757cabc-728e-466d-8c92-ca6c05bd3412" } ], "materials": [ { "number": 30, "shop_id": "0a04c659-682e-4049-b710-f47ebbd884cd" }, { "number": 50, "shop_id": "d757cabc-728e-466d-8c92-ca6c05bd3412" } ] } });
CREATE INDEX ix1 ON `bucket` (DISTINCT ARRAY v.shop_id FOR v WITHIN content END );
SELECT b.*
FROM (SELECT b.*, newcontect AS content
FROM `bucket` AS b
LET newcontect = (OBJECT o.name:o.val
FOR o IN (ARRAY {v.name ,
"val": (SELECT RAW f
FROM v.val AS f
WHERE f.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd")
}
FOR v IN OBJECT_PAIRS(b.content)
END)
WHEN o.val != []
END)
WHERE ANY v WITHIN b.content SATISFIES v.shop_id = "0a04c659-682e-4049-b710-f47ebbd884cd" END AND newcontect != {}
) AS b
WHERE ANY material IN b.content.materials SATISFIES material.`number` > 20 END;