RapidJson Object Array - rapidjson

I have a JSON file, which contains following information.
It is using array of objects. I want to retrieve name of "TetaInfo" object and value of "cad" object.
How can I do it?
{
"data": "group",
"name": "root",
"objects": {
"BOOT": {
"data": "group",
"name": "ProjectData",
"objects": {
"ModInfo": {
"data": "group",
"name": "Modformat",
"objects": {
"TetaInfo": {
"data": "group",
"name": "Tetaformat",
"objects": {
"Cad": {
"data": "text",
"name": "Cadingo",
"value": "CadValue6.0"
}
}
}
}
}
}
}
}
}

I am not exactly know your need. But you may try to use the newly added JSON Pointer API in RapidJSON, which can simplify the code and do check the validity of the path.
if (Value* v = GetValueByPointer(d, "/objects/BOOT/objects/ModInfo/objects/TetaInfo/objects/Cad"))
{
std::cout << (*v)["data"].GetString();
// ...
}
else {
// Unable to resolve the value of the pointer. Handle error.
}
GetValueByPointer() returns null when the pointer cannot be resolved in the document.

d["objects"]["BOOT"]["objects"]["ModInfo"]["objects"]["TetaInfo"]["objects"][ "Cad"] ="
std::string temp2 =d["objects"]["BOOT"]["objects"]["ModInfo"]["objects"]["TetaInfo"]["objects"][ "Cad"].GetString();
printf("\ntemp2 === %s",temp2.c_str());

Related

Sending array of objects in form-data. Swagger, OpenAPI 3

I am trying to send a form-data request which has an array of objects. The problem is that the data that I receive on my Express server comes in the form of an array in which all objects are turned into a string. I can't change anything in the server, I need to solve this problem using Swagger.
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"video[]": {
"type": "array",
"items": {
"type": "object",
"properties": {
"_id": {
"type": "string"
}
}
},
"describtion": "Video ids "
}
}
},
"encoding": {
"video[]": {
"contentType": "application/json",
"explode": true
}
}
}
}
},
What I expect on server: { video: [{ _id: "string" }] }
What I get: { video: [ '{"_id": "string"}' ] }
it seems you are not parsing the 'video' property. Try the below code in the controller function.
const {video} = req.body;
parsedVideo = JSON.parse(video);
console.log(parsedVideo);

How UNSET nested attribute?

I have such document:
{
"name": "FirstObj",
"attributes": {
"my_attributes/601890": {
"value": "Hellow World",
"id": "my_attributes/601890",
"name": "TEstAttr",
"myAttribute": "my_attributes/601890",
"_class": "MyAttributeValue"
}
},
"_class": "MyObj"
}
I cannot write AQL query which unsets "myAttribute": "my_attributes/601890". So i want to get such final document:
{
"name": "FirstObj",
"attributes": {
"my_attributes/601890": {
"value": "Hellow World",
"id": "my_attributes/601890",
"name": "TEstAttr",
"_class": "MyAttributeValue"
}
},
"_class": "MyObj"
}
Note, field attributes is object like key-value.(my_attributes/601890: {}) The field will be huge in the future
You can try to set the value to null and set the options keepNull to false to remove the field during the update.
For item in collection
UPDATE item
WITH {attributes: {"my_attributes/601890": {myAttribute: null}} }
IN collection
OPTIONS { keepNull: false }

How to traverse all Fields in all nested Records in an Avro file and check a certain property in their Types?

I have an avro file which has records, then in their fields (which have uniontypes) there are other records, which also have fields with union types, and some types have a certain property connect.name which i need to check if it equals to io.debezium.time.NanoTimestamp. I`m doing this in Apache NiFi using an ExecuteScript processor with Groovy script.
A shortened example of the Avro schema:
{
"type": "record",
"name": "Envelope",
"namespace": "data.none.bpm.pruitsmdb_nautilus_dbo.fast_frequency_tables.avro.test",
"fields": [
{
"name": "before",
"type": [
"null",
{
"type": "record",
"name": "Value",
"fields": [
{
"name": "Id",
"type": {
"type": "string",
"connect.parameters": {
"__debezium.source.column.type": "UNIQUEIDENTIFIER",
"__debezium.source.column.length": "36"
}
}
},
{
"name": "CreatedOn",
"type": [
"null",
{
"type": "long",
"connect.version": 1,
"connect.parameters": {
"__debezium.source.column.type": "DATETIME2",
"__debezium.source.column.length": "27",
"__debezium.source.column.scale": "7"
},
"connect.name": "io.debezium.time.NanoTimestamp"
}
],
"default": null
},
{
"name": "CreatedById",
"type": [
"null",
{
"type": "string",
"connect.parameters": {
"__debezium.source.column.type": "UNIQUEIDENTIFIER",
"__debezium.source.column.length": "36"
}
}
],
"default": null
}
],
"connect.name": "data.none.bpm.pruitsmdb_nautilus_dbo.fast_frequency_tables.avro.test.Value"
}
],
"default": null
},
{
"name": "after",
"type": [
"null",
"Value"
],
"default": null
},
{
"name": "source",
"type": {
"type": "record",
"name": "Source",
"namespace": "io.debezium.connector.sqlserver",
"fields": [
{
"name": "version",
"type": "string"
},
{
"name": "ts_ms",
"type": "long"
},
{
"name": "snapshot",
"type": [
{
"type": "string",
"connect.version": 1,
"connect.parameters": {
"allowed": "true,last,false"
},
"connect.default": "false",
"connect.name": "io.debezium.data.Enum"
},
"null"
],
"default": "false"
}
],
"connect.name": "io.debezium.connector.sqlserver.Source"
}
},
{
"name": "op",
"type": "string"
},
{
"name": "ts_ms",
"type": [
"null",
"long"
],
"default": null
}
],
"connect.name": "data.none.bpm.pruitsmdb_nautilus_dbo.fast_frequency_tables.avro.test.Envelope"
}
My Groovy code, which obviously seems to be checking the top-level records only, and also I'm not sure whether I'm checking the property connect.name correctly:
reader.forEach{ GenericRecord record ->
record.getSchema().getFields().forEach{ Schema.Field field ->
try {
field.schema().getTypes().forEach{ Schema typeSchema ->
if(typeSchema.getProp("connect.name") == "io.debezium.time.NanoTimestamp"){
record.put(field.name(), Long(record.get(field.name()).toString().substring(0, 13)))
typeSchema.addProp("logicalType", "timestamp-millis")
}
}
} catch(Exception ex){
println("Catching the exception")
}
}
writer.append(record)
}
My question is - how to traverse all nested Records (there are top-level records' fields which have "record" type and records inside) in the avro file? And when traversing their Fields - how to check correctly that one of their types (which may go in union) has a property connect.name == io.debezium.time.NanoTimestamp and if yes, perform a transformation on the field value and add a logicalType property to the field`s type?
I think you are looking for a recursion here - there should be a function that will accept the Record as a parameter. When you hit a field that is a nested record then you'll call this function recursively.
Jiri's approach suggestion worked, a recursive function was used, here`s the full code:
import org.apache.avro.*
import org.apache.avro.file.*
import org.apache.avro.generic.*
//define input and output files
DataInputStream inputStream = new File('input.avro').newDataInputStream()
DataOutputStream outputStream = new File('output.avro').newDataOutputStream()
DataFileStream<GenericRecord> reader = new DataFileStream<>(inputStream, new GenericDatumReader<GenericRecord>())
DataFileWriter<GenericRecord> writer = new DataFileWriter<>(new GenericDatumWriter<GenericRecord>())
def contentSchema = reader.schema //source Avro schema
def records = [] //list will be used to temporary store the processed records
//function which is traversing through all records (including nested ones)
def convertAvroNanosecToMillisec(record){
record.getSchema().getFields().forEach{ Schema.Field field ->
if (record.get(field.name()) instanceof org.apache.avro.generic.GenericData.Record){
convertAvroNanosecToMillisec(record.get(field.name()))
}
if (field.schema().getType().getName() == "union"){
field.schema().getTypes().forEach{ Schema unionTypeSchema ->
if(unionTypeSchema.getProp("connect.name") == "io.debezium.time.NanoTimestamp"){
record.put(field.name(), Long.valueOf(record.get(field.name()).toString().substring(0, 13)))
unionTypeSchema.addProp("logicalType", "timestamp-millis")
}
}
} else {
if(field.schema().getProp("connect.name") == "io.debezium.time.NanoTimestamp"){
record.put(field.name(), Long.valueOf(record.get(field.name()).toString().substring(0, 13)))
field.schema().addProp("logicalType", "timestamp-millis")
}
}
}
return record
}
//reading all records from incoming file and adding to the temporary list
reader.forEach{ GenericRecord contentRecord ->
records.add(convertAvroNanosecToMillisec(contentRecord))
}
//creating a file writer object with adjusted schema
writer.create(contentSchema, outputStream)
//adding records to the output file from the temporary list and closing the writer
records.forEach{ GenericRecord contentRecord ->
writer.append(contentRecord)
}
writer.close()

Elasticsearch query to match on one nested object, but return another

I have an ElasticSearch mapping as follows:
{
"person": {
"properties": {
"accounts": {
"type": "nested",
"properties": {
"username": {
"type": "string"
}
"account_type": {
"type": "string"
}
}
}
}
}
}
I want to write a query that matches the username for at least one of the nested accounts, but only returns the inner hit for the account that matches a specific type.
For example, for a person with accounts
{"accounts": [{"username": "Foo", "type": "foo-type"},
{"username": "Bar", "type": "bar-type"}]}}
I want a query that when searching for username "fo*", and type "bar-type", will return the user with an inner hit containing the nested object {"username": "Bar", "type": "bar-type"}, because the user has at least one account that matches the username, but the "bar-type" account type is always the one returned.
My query so far, looks like:
{
"query": {
"filtered": {
"query": {
"nested": {
"inner_hits": {
"size": 1
}
"path": "accounts",
"query": {
"bool": {
"must": [
{
"query": {
"wildcard": {
"accounts.username": {
"value": "fo*"
}
}
}
]
}
}
}
}
}
}
}
}
but (for obvious reasons) this returns the inner hit that matches the query. I'm not sure how to amend the query to return a different nested object that matches on the type "bar-type" as specified.

Count documents of certain type (filter against user before)

Documents (pseudo, rev and id omitted):
{
"type": 1,
"username": "aron",
"data": { ... }
}
{
"type": 1,
"username": "bob",
"data": { ... }
}
{
"type": 1,
"username": "steve",
"data": { ... }
}
{
"type": 1,
"username": "steve",
"data": { ... }
}
{
"type": 2,
"username": "steve",
"data": { ... }
}
{
"type": 3,
"username": "steve",
"data": { ... }
}
{
"type": 3,
"username": "steve",
"data": { ... }
}
{
"type": 3,
"username": "steve",
"data": { ... }
}
I want to know, how many documents of type 1/2/3 steve has.
View:
count: {
map: function (doc) {
emit([doc.username, doc.type], 1);
}
reduce: function (key, values, rereduce) {
return sum(values);
}
}
Now I request
/database/_design/myDesign/_view/count?key=["steve",1] // result: 2
/database/_design/myDesign/_view/count?key=["steve",2] // result: 1
/database/_design/myDesign/_view/count?key=["steve",3] // result: 3
This works perfectly well.
To smart things up, I was wondering if I can query that in one view?
Is there a way to count the number of documents of unknown number of types in one view?
You can POST to your view with a body like this;
{"keys":[["steve",1], ["steve",2]]}
Also, try using "_sum" as your reduce function, it will run natively in Erlang and should be several times faster than doing it in Javascript.
You can perform a range query to achieve this:
.../count?startkey=["steve",1]&endkey=["steve",3]&group=true&reduce=true
This will fetch one line for every key between ["steve",1] and ["steve",3] inclusive. You can adjust values 0 and 3 according to what your types can actually be. For instance, if your types can be any scalar value, you can use ["steve",null] and ["steve",{}] as the range boundaries.

Resources