I'm using MarkLogic json:transform-to-json to produce JSON from XML. I can't figure out the right config options to skip the root element in the XML, and only show the immediate children and further descendants.
I do
import module namespace json="http://marklogic.com/xdmp/json"
at "/MarkLogic/json/json.xqy";
let $jsonConfig := json:config("custom")
=> map:with("whitespace","ignore")
=> map:with("array-element-names",'genre')
let $payLoad :=
<root>
<name>The Beatles</name>
<genre>rock</genre>
<genre>pop</genre>
<genre>beat</genre>
<genre>psychedelia</genre>
</root>
return json:transform-to-json($payLoad,$jsonConfig)
I get
{
"root": {
"name": "The Beatles",
"genre": [
"rock",
"pop",
"beat",
"psychedelia"
]
}
}
I want to get
{
"name": "The Beatles",
"genre": [
"rock",
"pop",
"beat",
"psychedelia"
]
}
Any help is appreciated.
I note that the sample does not run as expected. I think you meant this line for the config: => map:with("array-element-names",'genre')
As for what you are doing: If you are storing this in MarkLogic, then I would urge you to keep the extra level at the top with "root". This will play well with some items in MarkLogic like the "context" for TDE templates.
However if you prefer to remove it, there is no configuration - instead, simply x-path to what you want:
import module namespace json="http://marklogic.com/xdmp/json"
at "/MarkLogic/json/json.xqy";
let $jsonConfig := json:config("custom")
=> map:with("whitespace","ignore")
=> map:with("array-element-names",'genre')
let $payLoad :=
<root>
<name>The Beatles</name>
<genre>rock</genre>
<genre>pop</genre>
<genre>beat</genre>
<genre>psychedelia</genre>
</root>
return json:transform-to-json($payLoad,$jsonConfig)/root
Resulting in:
{
"name": "The Beatles",
"genre": [
"rock",
"pop",
"beat",
"psychedelia"
]
}
Related
I have a json schema that marks special properties in need of processing and I want to query those via JsonPath.Evaluate.
Here's a part of the schema to illustrate the issue
{
"type": "object",
"properties": {
"period": {
"description": "The period in which the rule applies",
"type": "object",
"properties": {
"start": {
"type": "string",
"format": "date-time"
},
"end": {
"type": "string",
"format": "date-time"
}
},
"required": [
"start"
],
"x-updateIndicatorProperties": [
"start"
]
},
"productType": {
"type": "string"
},
"x-updateIndicatorProperties": [
"productType"
]
}
}
I want to get the the JsonPath of the "x-updateIndicatorProperties" properties, so that I can then query the actual properties to process.
For this example, the expected result would be
[
"$['properties']['x-updateIndicatorProperties']",
"$['properties']['period']['x-updateIndicatorProperties']"
]
I've been trying for a while to get a JsonPath expression that would query these properties.
Currently I'm just iterating all properties and filter them manually :
"$..*"
I've also tried using :
$..['x-updateIndicatorProperties']
This works. But it returns a lot of duplicates. For the example above, I get 5 results instead of the expected 2. Can be demonstrated here : https://json-everything.net/json-path
Assuming I can't influence the schema itself, only the code that traverses it,
can anybody help with an expression to get the expected results or any other way to achieve the same outcome?
The stack is JsonPath 0.2.0, .net 6 and system.text.json.
This was a bug in the library when parsing paths that use a recursive descent (..) into a quoted-property-name selector (['foo']). So it would happen for any path in the form $..['foo'].
I've fixed the issue and released version 0.2.1.
I have a JSON object(Form) in the mongo collection like this
{
"_id": "87124eb6-c9f7-49b9-8470-8c2b7fb07dc8",
"VisitName": "demo visit",
"Version": "string",
"FormStatus": "string",
"FormName": "demo form",
"IsDeleted": false,
"Pages": [
{
"PageName": "demo page",
"PageNo": 1,
"PageStatus": true,
"Field": [
{
"FieldName": "Gender",
"Value": "demo value",
"Comment": "demo comment",
}
]
}
]
}
I need to edit the Field (which is an array of objects ).
Currently, I am loading the full form and replacing the field data to be updated, Then replace the new form with the old one.
loading the whole form for each field update may affect performance, when loading large forms
Is there any way to update only the field details with fieldName(Unique) Instead of fetching the whole Form and editing?
Update: I missed the ASP.NET tag before answering this. I hope, this still gets you to the solution
You can use an update with arrayFilters. Here's a playground link to test it.
db.collection.update({
"FormName": "demo form"
},
{
$set: {
"Pages.$[pageItem].Field.$[fieldItem].Value": "new value"
}
},
{
arrayFilters: [
{
"pageItem.PageName": "demo page"
},
{
"fieldItem.FieldName": "Gender"
}
]
})
Basically, you tell MongoDB, update the nested field in the corresponding array element, that fulfils the filter specified by arrayFilters. So in this case, you update the path: "Pages.$[pageItem].Field.$[fieldItem].Value" to the new value but only in those nested documents, that:
reside in a page, whose name is demo page
and, in that page, there is a filed, whose name is Gender
Goal: Deploy an Azure Policy to a management group so when certain tags are missing from a resource within its remit, apply the specified Tag from the resource group
Problem: Deploying this template to the management group results in "'The template function 'RESOURCEGROUP' is not expected at this location."
There is a fairly plain structure similar to:
<Management Group> - <Subscription 1> - <Resource Group 1> - <Resource A>
- <Resource Group 2> - <Resource B>
- <Subscription 2> - <Resource Group 3> - <Resource C>
- <Resource D>
There is a fairly simple template using a nested policy definition:
......
"resources": [
{
"type": "Microsoft.Authorization/policyDefinitions",
"apiVersion": "2019-09-01",
"name": ".",
"properties": {
"policyType": "Custom",
"mode": "Indexed",
"displayName": ".",
"description": ".",
"metadata": {
"category": "Tags"
},
"policyRule": {
"if": {
"anyOf": [
{
"field": "tags['costCenter']",
"exists": "false"
},
{
"field": "tags['CostCenter']",
"notin": "[parameters('allowedCostCenter')]"
}
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/4a9ae827-6dc8-4573-8ac7-8239d42aa03f"
],
"operations": [
{
"operation": "add",
"field": "tags['CostCenter']",
"value": "[resourcegroup().tags['CostCenter']]"
}
]
}
}
}
}
}
]
I realise that you can not use "resourcegroup()" on items that are not within a resource group, but the guides suggested using this within the nested template and on "indexed" resources should work.
I'm fairly sure the pipeline is correct as I already have several audit policies deploying
From experimenting in the portal, this looks like it should be possible
There is a decent amount of reading around, but I have not read (or at least understood) that seems to help with this
Is what I am trying to achieve possible? If so, can you see what I am doing wrong?
Thanks for your help!
You need to add escape character if you want resourcegroup() function to be executed as a part of the Azure Policy, not the MG-scope ARM template:
"value": "[[resourcegroup().tags['CostCenter']]"
The following is my structure of data
[
{
"id": 1,
"title": "Welcome to my playground",
"description": "This is so fun to play with, you will like it <3",
"comments": [
{
"id": 1140406,
"comment": "this is an example comment",
"postId": 1
}
]
},
...
]
And I'm trying to use immutable js to do this operation
Get all the posts
Search for a post I want to add comment to
Adding the comments when the post is found
The following is my code
posts = posts.map((post) => {
if(post.get('id') == payload.post_id) {
return post.update('comments', (comments) => {
return comments.push(Map({
id: payload.id,
comment: payload.comment
}));
});
}
return post;
});
But I assume this pattern is very common and there should be a simpler way to do this in immutableJS. Any advice will be helpful, thanks.
First off, it's worth mentioning that your Data structure is Immutable Lists and Maps.. not JS Arrays and Objects.
OK, without changing your data structure you could do:
posts.map(post => post.get('id') === payload.post_id ?
post.update('comments', comments.push(payload) :
post)
If you were to change your data structure, and instead of having a List of posts, had a Map of post's with their ID as the key you could just do:
post.updateIn([payload.post_id, 'comments'], comments => comments.push(payload))
BTW you can use push or concat here, both will function the same.
Also, if comments may be undefined, you can provide a "noSetValue" as a List (https://facebook.github.io/immutable-js/docs/#/List/updateIn):
posts.map(post => post.get('id') === payload.post_id ?
post.update('comments', Immutable.List([]), comments.push(payload) :
post)
post.updateIn([payload.post_id, 'comments'], Immutable.List([]), comments => comments.push(payload))
For others who has the same question: One should consider a data normalisation (search for normalizr). You could then normalise your data to something like:
"entities": {
"posts": {
"1": {
"id": 1,
"title": "Welcome to my playground",
"description": "This is so fun to play with, you will like it <3",
"comments": [1140406, 1140407, 1140408]
},
"42" : {...}
}
"comments": {
"1140406": {
"id": 1140406,
"comment": "this is an example comment",
"postId": 1
},
"1140407": {...}
}
}
then updating post and comments becomes much easier
I have a document with this structure:
[{
"id": "test",
"StudentRules": [
{
"id": "d8b730905",
"name": "Test",
"ruletype": "Allow",
"startdate": "5/7/2015 10:05:15 AM"
}
]
I need to write a query that will give me all the "StudentRules" for a given id "test".
I wrote this:
select * from json j where j.id = "test"
This returns the structure as the example above.
I am expecting this:
[
{
"id": "d8b730905",
"name": "Test",
"ruletype": "Allow",
"startdate": "5/7/2015 10:05:15 AM"
}
]
The idea is to have all the rules in a list which will be shown in an MVC application.
Any help is greatly appreciated.
Thanks in advance.
Regards.
You can use the JOIN keyword to form cross products with nested array elements:
SELECT Rule.id, Rule.name, Rule.ruletype, Rule.startdate
FROM root
JOIN Rule IN root.StudentRules
WHERE root.id = "test"
You may find looking at the sample queries on DocumentDB's query playground useful.