I'm new to CouchDB and struggling to implement a basic example. I have three documents Customer, Contact, Address and I want join them into a single document.
Account Document
{
"_id": "CST-1",
"_rev": "8-089da95f148b446bd3b33a3182de709f",
"name": "Customer",
"code": "CST-001",
"contact_Key": "CNT-001",
"address_Key": "ADD-001",
"type": "Customer"
}
Contact Document
{
"_id": "CNT-001",
"_rev": "8-079da95f148b446bd3b33a3182de709g",
"fullname": "Happy Swan",
"type": "Contact"
}
Address Document
{
"_id": "ADD-001",
"_rev": "8-179da95f148b446bd3b33a3182de709c",
"street1": "9 Glass View",
"street2": "Street 2",
"city": "USA",
"type": "Address"
}
Map/Query:
var map= function (doc) {
if (doc.type === 'Customer') {
emit(doc.id, { contact_Key: doc.contact_Key, address_Key: doc.address_Key })
}
};
db.query({ map: map }, { include_docs: true }, function (err, res) {
});
I want all 3 documents in a single document when I query account e.g.
Expected result
{
"_id": "CST-1",
"_rev": "8-089da95f148b446bd3b33a3182de709f",
"name": "Customer",
"code": "CST-001",
"contact_Key": "CNT-001",
"address_Key": "ADD-001",
"type": "Customer",
"Contact: {
"_id": "CNT-001",
"_rev": "8-079da95f148b446bd3b33a3182de709g",
"fullname": "Happy Swan",
"type": "Contact"
}",
"Address: {
"_id": "ADD-001",
"_rev": "8-179da95f148b446bd3b33a3182de709c",
"street1": "9 Glass View",
"street2": "Street 2",
"city": "USA",
"type": "Address"
}"
}
I don't see any better solution than querying the account document first and then querying the other two once you know their IDs. If you think about it, it makes sense because the only link between these documents is the IDs stored in the account document, so to get all three at the same time, internally the DB would have to do two queries: first the account document, then the other two. And by design CouchDB only does one query at a time.
If you had the account doc ID stored into the contact and address documents however, you could use a list function to merge them all into one.
First you would need a view:
function(doc) {
if (doc.type === 'Customer') {
emit(doc._id, doc);
}
if (doc.type === 'Contact' || doc.type === 'Address') {
emit(doc.account_id, doc);
}
}
Then a list function:
function(head, req) {
var row, account, contact, address;
while (row = getRow()) {
if (row.value.type === 'Customer') {
account = row.value;
} else if (row.value.type === 'Contact') {
contact = row.value;
} else if (row.value.type === 'Address') {
address = row.value;
}
}
account['Contact'] = contact;
account['Address'] = address;
provides("json", function() {
return { 'json': account };
});
}
And you would query it with:
GET /db/_design/foo/_list/the-list/the-view?key="CST-1"
Related
I was able to create author nodes directly from the json file . But the challenge is on what basis or how we have to link the data. Linking "Author" to "organization". since the data is dynamic we cannot generalize it. I have tried with using csv file but, it fails the conditions when dynamic data is coming. For example one json record contain 2 organization and 3 authors, next record will be different. Different json record have different author and organization to link. organization/1 represent organization1 and organization/2 represents organization 2. Any help or hint will be great. Thank you. Please find the json file below.
"Author": [
{
"seq": "3",
"type": "abc",
"identifier": [
{
"idtype:auid": "10000000"
}
],
"familyName": "xyz",
"indexedName": "MI",
"givenName": "T",
"preferredName": {
"familyName": "xyz1",
"givenName": "a",
"initials": "T.",
"indexedName": "bT."
},
"emailAddressList": [],
"degrees": [],
"#id": "https:abc/2009127993/author/person/3",
"hasAffiliation": [
"https:abc/author/organization/1"
],
"organization": [
[
{
"identifier": [
{
"#type": "idtype:uuid",
"#subtype": "idsubtype:affiliationInstanceId",
"#value": "aff2"
},
{
"#type": "idtype:OrgDB",
"#subtype": "idsubtype:afid",
"#value": "12345"
},
{
"#type": "idtype:OrgDB",
"#subtype": "idsubtype:dptid"
}
],
"organizations": [],
"addressParts": [],
"sourceText": "",
"text": " Medical University School of Medicine",
"#id": "https:abc/author/organization/1"
}
],
[
{
"identifier": [
{
"#type": "idtype:uuid",
"#subtype": "idsubtype:affiliationInstanceId",
"#value": "aff1"
},
{
"#type": "idtype:OrgDB",
"#subtype": "idsubtype:afid",
"#value": "7890"
},
{
"#type": "idtype:OrgDB",
"#subtype": "idsubtype:dptid"
}
],
"organizations": [],
"addressParts": [],
"sourceText": "",
"text": "K University",
"#id": "https:efg/author/organization/2"
}
]
Hi I see that Organisation is part of the Author data, so you have to model it like wise. So for instance (Author)-[:AFFILIATED_WITH]->(Organisation)
When you use apoc.load.json which supports a stream of author objects you can load the data.
I did some checks on your JSON structure with this cypher query:
call apoc.load.json("file:///Users/keesv/work/check.json") yield value
unwind value as record
WITH record.Author as author
WITH author.identifier[0].`idtype:auid` as authorId,author, author.organization[0] as organizations
return authorId, author, organizations
To get this working you will need to create include apoc in the plugins directory, and add the following two lines in the apoc.conf file (create one if it is not there) in the 'conf' directory.
apoc.import.file.enabled=true
apoc.import.file.use_neo4j_config=false
I also see a nested array for the organisations in the output why is that and what is the meaning of that?
And finally I see also in the JSON that an organisation can have a reference to other organisations.
explanation
In my query I use UNWIND to unwind the base Author array. This means you get for every author a 'record' to work with.
With a MERGE or CREATE statement you can now create an Author Node with the correct properties. With the FOREACH construct you can walk over all the Organization entry and create/merge an Organization node and create the relation between the Author and the Organization.
here an 'psuedo' example
call apoc.load.json("file:///Users/keesv/work/check.json") yield value
unwind value as record
WITH record.Author as author
WITH author.identifier[0].`idtype:auid` as authorId,author, author.organization[0] as organizations
// creating the Author node
MERGE (a:Author { id: authorId })
SET a.familyName = author.familyName
...
// walk over the organizations
// determine
FOREACH (org in organizations |
MERGE (o:Organization { id: ... })
SET o.name = org.text
...
MERGE (a)-[:AFFILIATED_WITH]->(o)
// if needed you can also do a nested FOREACH here to process the Org Org relationship
)
Here is the JSON file I used I had to change something at the start and the end
[
{
"Author":{
"seq":"3",
"type":"abc",
"identifier":[
{
"idtype:auid":"10000000"
}
],
"familyName":"xyz",
"indexedName":"MI",
"givenName":"T",
"preferredName":{
"familyName":"xyz1",
"givenName":"a",
"initials":"T.",
"indexedName":"bT."
},
"emailAddressList":[
],
"degrees":[
],
"#id":"https:abc/2009127993/author/person/3",
"hasAffiliation":[
"https:abc/author/organization/1"
],
"organization":[
[
{
"identifier":[
{
"#type":"idtype:uuid",
"#subtype":"idsubtype:affiliationInstanceId",
"#value":"aff2"
},
{
"#type":"idtype:OrgDB",
"#subtype":"idsubtype:afid",
"#value":"12345"
},
{
"#type":"idtype:OrgDB",
"#subtype":"idsubtype:dptid"
}
],
"organizations":[
],
"addressParts":[
],
"sourceText":"",
"text":" Medical University School of Medicine",
"#id":"https:abc/author/organization/1"
}
],
[
{
"identifier":[
{
"#type":"idtype:uuid",
"#subtype":"idsubtype:affiliationInstanceId",
"#value":"aff1"
},
{
"#type":"idtype:OrgDB",
"#subtype":"idsubtype:afid",
"#value":"7890"
},
{
"#type":"idtype:OrgDB",
"#subtype":"idsubtype:dptid"
}
],
"organizations":[
],
"addressParts":[
],
"sourceText":"",
"text":"K University",
"#id":"https:efg/author/organization/2"
}
]
]
}
}
]
IMPORTANT create unique constraints for Author.id and Organization.id!!
In this way you can process any json file with an unknown number of author elements and an unknown number of affiliated organisations
Is it possible to add "bpmn:Resource" element in propertiesPanel and edit its attribute? how to do it?
I've already added some properties to property panel based on the property-panel[link] example.
But I have a challenge in adding 'bpmn:Resource' to the properties panel. I don't want it to be added as an extensionElement.
I'd like it to be inside bpmn:Definitions (beside bpmn:Process). Also I'd like to extend the original bpmn:Resource to add some parameters.
So in MyModdle.json I added:
{
"name": "Resource",
"extends": [
"bpmn:Resource"
],
"properties": [
{
"name": "parameters",
"isMany": true,
"type": "MyParameter"
}
]
}, {
"name": "MyParameter",
"properties": [
{
"name": "myParameterType",
"isAttr": true,
"type": "String"
}
{
"name": "myParameterName",
"isAttr": true,
"type": "String"
},
{
"name": "myParameterValue",
"isAttr": true,
"type": "String"
}
]
}
now for example in newElement function of MyResource.js
var newElement = function (type, prop, factory) {
return function (element, extensionElements, value) {
var commands = [];
var resource = getResource(element);
if (!resource) {
var parent = extensionElements;
resource = createResource(parent, bpmnFactory);
console.log('resource', resource);
commands.push(cmdHelper.addAndRemoveElementsFromList(
element,
extensionElements,
'values',
'extensionElements',
[resource],
[]
));
}
var newElem = createResourceParameter(type, resource, bpmnFactory, {
resourceId: 'id-' + value
});
commands.push(cmdHelper.addElementsTolist(element, parameters, prop, [newElem]));
return commands;
};
}
I know this cmdHelper adds 'bpmn:Resource' to extensionElements but I don't know what to use instead!
I am using webix to show some tree table data.
webix.ready(function () {
grida = webix.ui({
container: "testB",
view: "treetable",
columns: [
{ id: "id", header: "", css: { "text-align": "right" } },
{
id: "SerialNo", header: "Serial No", width: 250,
template: "{common.treetable()} #SerialNo#"
}
],
url: "/Test/GetTreeItem",
autoheight: true,
});
});
This loads the items perfectly.
Parents;
[{"id":11583,"Id":11583,"SerialNo":"12476127654","webix_kids":1},{"id":11584,"Id":11584,"SerialNo":"125235463","webix_kids":1},{"id":11585,"Id":11585,"SerialNo":"21385423348956","webix_kids":1},{"id":11586,"Id":11586,"SerialNo":"253346346346","webix_kids":1},{"id":11587,"Id":11587,"SerialNo":"123123","webix_kids":1},{"id":11588,"Id":11588,"SerialNo":"52354263","webix_kids":1},{"id":11589,"Id":11589,"SerialNo":"12344444","webix_kids":1},{"id":11590,"Id":11590,"SerialNo":"12344444","webix_kids":1},{"id":11591,"Id":11591,"SerialNo":"12344444","webix_kids":1},{"id":11592,"Id":11592,"SerialNo":"151515","webix_kids":1}]
However when I click the plus button, server returns (I can see the json string when I debug the code) the json but webix not appending the data underneath the parent.
Kids of parent "id":11587;
[{"id":11583,"Id":11583,"SerialNo":"12476127654","webix_kids":1},{"id":11592,"Id":11592,"SerialNo":"151515","webix_kids":1}]
id of data object must be unique per component.
Currently, you have for top level
{
"id": 11583,
"Id": 11583,
"SerialNo": "12476127654",
"webix_kids": 1
},
and in kids data you have
{
"id": 11583,
"Id": 11583,
"SerialNo": "12476127654",
"webix_kids": 1
},
both items share the same id, so treetable doesn't add a new item.
Correcting the JSON output solved my problem.
For the parents;
{
"parent":"0",
"data":[
{
"Id":11584,
"id":11584,
"SerialNo":"125235463",
"webix_kids":1
},
{
"Id":11599,
"id":11599,
"SerialNo":"3444",
"webix_kids":1
}
]
}
For the kids;
{
"parent":11599,
"data":[
{
"id":11583,
"Id":11583,
"SerialNo":"12476127654",
"webix_kids":1
},
{
"id":11592,
"Id":11592,
"SerialNo":"151515",
"webix_kids":1
}
]
}
I'm attempting to loop through a JSON array sending data to a struct.
Here's my code that uses SwiftyJSON to return a JSON object:
performAPICall() {
json in
if(json != nil){
print("Here is the JSON:")
print(json["content"]["clients"])
let clients = json["content"]["clients"]
for client in clients {
var thisClient = Client()
thisClient.id = client["id"].string
thisClient.desc = client["desc"].string
thisClient.name = client["name"].string
self.clientArray.append(thisClient)
}
self.tableView.reloadData()
} else {
print("Something went very wrong..,")
}
}
I'm not quite sure why I'm getting "has no subscript" errors on the three strings.
Any help appreciated, thanks.
EDIT: Here's a sample of the JSON
{
"content": {
"clients": [{
"group": "client",
"id": "group_8oefXvIRV4",
"name": "John Doe",
"desc": "John's group."
}, {
"group": "client",
"id": "group_hVqIc1eEsZ",
"name": "Demo Client One",
"desc": "Demo Client One's description! "
}, {
"group": "client",
"id": "group_Yb0vvlscci",
"name": "Demo Client Two",
"desc": "This is Demo Client Two's group"
}]
}
}
You should use array method. Thus, your line
let clients = json["content"]["clients"]
should use array (and unwrap it safely):
guard let clients = json["content"]["clients"].array else {
print("didn't find content/clients")
return
}
// proceed with `for` loop here
I am building my search query for some listing data. As part of the search people can ask for multiple rooms which sleeps a min amount of people, ie two rooms which sleep 2 and 3 people.
Im not sure how I can perform that with a filter.
Here is a shortened search query so far.
{
"query":{
"filtered":{
"query":{
"match_all":{}
}
}
},
"filter":{
"and":
[
{
"term":{
"status":"live"
}
},
{
"geo_bounding_box":{
"location":{
"top_left":"60.856553, -8.64935719999994",
"bottom_right":"49.8669688, 1.76270959999999"
}
}
}
,{
"range":{
"bedrooms":{
"gte":"2"
}
}
}
]
}
,
"size":10
}
Test Data
{
"took":1,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"failed":0
},
"hits":{
"total":3,
"max_score":1.0,
"hits":[
{
"_index":"listings",
"_type":"listing",
"_id":"1",
"_score":1.0,
"_source":{
"name:":"Listing One",
"address1":"Some Street",
"bedrooms":2,
"city":"A City",
"id":1,
"refno":"FI451",
"user_id":1,
"rooms":[
{
"bathroom":"Shared bathroom with bath",
"double_standard":null,
"id":5,
"single":2,
"sleeps":2,
"title":"Twinny",
},
{
"bathroom":"Ensuite with bath",
"double_king_size":1,
"double_standard":1,
"id":1,
"single":null,
"sleeps":2,
"title":"Double Ensuite Room",
}
]
}
},
{
"_index":"listings",
"_type":"listing",
"_id":"2",
"_score":1.0,
"_source":{
"name":"Listing Two",
"address1":"Some Street",
"bedrooms":2,
"city":"A City",
"id":2,
"refno":"BL932",
"user_id":1,
"rooms":[
{
"bathroom":"Ensuite with bath",
"double_standard":1,
"id":4,
"single":1,
"sleeps":3,
"title":"Family Room",
},
{
"bathroom":"Ensuite with shower",
"double_standard":1,
"id":2,
"single":null,
"sleeps":2,
"title":"Single Room",
}
]
}
},
{
"_index":"listings",
"_type":"listing",
"_id":"3",
"_score":1.0,
"_source":{
"name":"Listing Three",
"address1":"Another Address",
"bedrooms":1,
"city":"Your City",
"id":3,
"refno":"TE2116",
"user_id":1,
"rooms":[
{
"bathroom":"Ensuite with shower",
"double_king_size":null,
"double_standard":1,
"id":3,
"single":1,
"sleeps":3,
"title":"Family Room",
}
]
}
}
]
}
}
If you look at my data I have 3 listings, two of them have multiple rooms (Listing One & Two) but only Listing Two would match my search, Reason it has one room with that sleeps two and the other sleeps three.
Is it possible to perform this query with elasticsearch?
If what you want is "Find all listings where a bedroom sleeps 2 AND another bedroom sleeps 3", this query will work. It makes one big assumptions: that you are using inner objects, and not the Nested data type.
This query is using the fact that inner objects are collapsed into a single field, causing "rooms.sleeps" to equal [2,3] for the desired field. Since the field is collapsed into a single array, a simple Terms query will match them. When you change the execution mode to And, it forces both 2 and 3 to be matched.
The caveat is that a room that has [2,3,4] will also be matched.
I've omitted the geo and status portion since that data wasn't provided in the source documents.
{
"query": {
"filtered": {
"query": {
"match_all": {}
}
}
},
"filter": {
"and": [
{
"range": {
"bedrooms": {
"gte": "2"
}
}
},
{
"terms": {
"rooms.sleeps": [2,3],
"execution": "and"
}
}
]
},
"size": 10
}
As far as I know the filter has to be a sibling of the query inside the filtered element. See: http://www.elasticsearch.org/guide/reference/query-dsl/filtered-query/
If you combine that with Zach's solution it should work.
{
"query":
{
"filtered":
{
"query":
{
"match_all":{}
},
"filter":
{
"put" : "your filter here"
}
}
}
}