Related
I'm currently working on a wordpress site. I created a relationship field called link_to_content basically what I', trying to do is to connect a tout to a program. The relationship field is set to return a Post Object.
So when I go into the tout and select the program schoolFood as the value for link_to_content I should be getting the object with the porgram's data.
Instead what I get is an array with the program's id.
{{ dump(tout.link_to_content) }}
I also see from the ACF JSON file the field being updated
+ "label": "Link Content",
+ "name": "link_to_content",
+ "type": "relationship",
+ "instructions": "",
+ "required": 0,
+ "conditional_logic": [
+ [
+ {
+ "field": "field_5f21c1d39f170",
+ "operator": "==",
+ "value": "Internal"
+ }
+ ]
+ ],
+ "wrapper": {
+ "width": "",
+ "class": "",
+ "id": ""
+ },
+ "show_in_rest": 0,
+ "wpml_cf_preferences": 0,
+ "post_type": [
+ "post",
+ "page",
+ "programs",
+ "location"
+ ],
+ "taxonomy": "",
+ "filters": [
+ "search",
+ "post_type",
+ "taxonomy"
+ ],
+ "elements": "",
+ "min": "",
+ "max": "",
+ "return_format": "object"
+ },
Any idea on why this might be?
I'm using firebase-tools emulator to locally test saving a record to Cloud Firestore.
$ firebase serve --only functions,firestore
i firestore: Serving ALL traffic (including WebChannel) on http://localhost:8080
⚠ firestore: Support for WebChannel on a separate port (8081) is DEPRECATED and will go away soon. Please use port above instead.
i firestore: Emulator logging to firestore-debug.log
⚠ Your requested "node" version "8" doesn't match your global version "12"
✔ functions: Emulator started at http://localhost:5000
✔ firestore: Emulator started at http://localhost:8080
My code:
// FirestoreConnection.ts
import {firestore} from "firebase-admin";
export default class FirestoreConnection {
protected shopDomain: string;
protected database: firestore.Firestore;
constructor(shopDomain: string, database: firestore.Firestore) {
this.shopDomain = shopDomain;
this.database = database;
}
// --------------- Public Methods
public async createNew(type: RecordTypes, documentData: object): Promise<firestore.DocumentSnapshot|null> {
try {
return await this.addDocument(collectionName, documentData);
}
catch (e) {
console.log(e, `=====error createNew()=====`);
return null;
}
}
// --------------- Protected/Private Methods
protected async addDocument(collectionName: string, documentData: object): Promise<firestore.DocumentSnapshot|null> {
try {
const newlyAddedDocument = await this.database
.collection(collectionName)
.add(documentData);
return await newlyAddedDocument.get();
}
catch (e) {
console.log(e, `=====error addDocument()=====`);
return null;
}
}
// FirestoreConnection.test.ts
import * as firebaseTesting from "#firebase/testing";
import {Logger} from "#firebase/logger";
import {RecordTypes} from "../../../../shared";
import FirestoreConnection from "../FirestoreConnection";
/* * * * * * * * * * * * * * * * * * * * *
Setup
* * * * * * * * * * * * * * * * * * * * */
// setup firebase logging
const logClient = new Logger("#firebase/testing");
logClient.log("FirestoreConnection.test.ts");
// --------------- Helpers
const createTestDatabase = (credentials): any => {
return firebaseTesting
.initializeTestApp({
projectId: 'testproject',
auth: credentials
})
.firestore();
};
const nullAllApps = firebaseTesting
.apps().map(app => app.delete());
const db = new FirestoreConnection('testshopdomain', createTestDatabase(null));
// --------------- Before / After
beforeEach(() => {
});
afterEach(async () => {
try {
await Promise.all(nullAllApps);
await firebaseTesting.clearFirestoreData({
projectId : "testproject"
})
}
catch (e) {
console.log(e, `=====error=====`);
}
});
/* * * * * * * * * * * * * * * * * * * * *
Tests
* * * * * * * * * * * * * * * * * * * * */
test("creates new record", async () => {
try {
const addedDocument = await db
.createNew(RecordTypes.globalRule, {
storeId : "dummystoreid"
, globalPercent : 40
});
expect(addedDocument).toEqual({
storeId : "dummystoreid"
, globalPercent : 40
, badProp : 0
});
}
catch (e) {
console.log(e, `=====error test("creates new record"=====`);
}
}, 100000);
I receive a long error when running jest. Thousands of rows show + 118, or similar number, along with object properties, all red text. Then a stack trace in white text.
// terminal
+ 116,
+ 111,
+ 51,
// continues for thousands of lines...
+ ],
+ "type": "Buffer",
+ },
+ ],
+ "format": "Protocol Buffer 3 DescriptorProto",
+ "type": Object {
+ "enumType": Array [],
+ "extension": Array [],
+ "extensionRange": Array [],
+ "field": Array [
+ Object {
+ "defaultValue": "",
+ "extendee": "",
+ "jsonName": "",
+ "label": "LABEL_OPTIONAL",
+ "name": "updateTime",
+ "number": 1,
+ "oneofIndex": 0,
+ "options": null,
+ "type": "TYPE_MESSAGE",
+ "typeName": "protobuf.Timestamp",
+ },
+ Object {
+ "defaultValue": "",
+ "extendee": "",
+ "jsonName": "",
+ "label": "LABEL_REPEATED",
+ "name": "transformResults",
+ "number": 2,
+ "oneofIndex": 0,
+ "options": null,
+ "type": "TYPE_MESSAGE",
+ "typeName": "Value",
+ },
+ ],
+ "name": "WriteResult",
+ "nestedType": Array [],
+ "oneofDecl": Array [],
+ "options": null,
+ "reservedName": Array [],
+ "reservedRange": Array [],
+ },
+ },
+ },
+ },
+ "credentialsProvider": FirebaseCredentialsProvider {
+ "auth": null,
+ "changeListener": [Function anonymous],
+ "currentUser": User {
+ "uid": null,
+ },
+ "forceRefresh": false,
+ "receivedInitialUser": true,
+ "tokenCounter": 1,
+ "tokenListener": [Function anonymous],
+ },
+ "handshakeComplete_": true,
+ "idleTimer": DelayedOperation {
+ "asyncQueue": AsyncQueue {
+ "_isShuttingDown": false,
+ "delayedOperations": Array [
+ [Circular],
+ ],
+ "failure": null,
+ "operationInProgress": true,
+ "tail": Promise {},
+ "timerIdsToSkip": Array [],
+ },
+ "catch": [Function bound catch],
+ "deferred": Deferred {
+ "promise": Promise {},
+ "reject": [Function anonymous],
+ "resolve": [Function anonymous],
+ },
+ "op": [Function anonymous],
+ "removalCallback": [Function anonymous],
+ "targetTimeMs": 1579867383588,
+ "then": [Function bound then],
+ "timerHandle": Timeout {
+ "_destroyed": false,
+ "_idleNext": TimersList {
+ "_idleNext": [Circular],
+ "_idlePrev": [Circular],
+ "expiry": 79350,
+ "id": -9007199254740987,
+ "msecs": 60000,
+ "priorityQueuePosition": 1,
+ },
+ "_idlePrev": TimersList {
+ "_idleNext": [Circular],
+ "_idlePrev": [Circular],
+ "expiry": 79350,
+ "id": -9007199254740987,
+ "msecs": 60000,
+ "priorityQueuePosition": 1,
+ },
+ "_idleStart": 19350,
+ "_idleTimeout": 60000,
+ "_onTimeout": [Function anonymous],
+ "_repeat": null,
+ "_timerArgs": undefined,
+ Symbol(refed): true,
+ Symbol(asyncId): 152,
+ Symbol(triggerId): 0,
+ },
+ "timerId": "write_stream_idle",
+ },
+ "idleTimerId": "write_stream_idle",
+ "lastStreamToken": Object {
+ "data": Array [
+ 49,
+ ],
+ "type": "Buffer",
+ },
+ "listener": Object {
+ "onClose": [Function bound ],
+ "onHandshakeComplete": [Function bound ],
+ "onMutationResult": [Function bound ],
+ "onOpen": [Function bound ],
+ },
+ "queue": AsyncQueue {
+ "_isShuttingDown": false,
+ "delayedOperations": Array [
+ DelayedOperation {
+ "asyncQueue": [Circular],
+ "catch": [Function bound catch],
+ "deferred": Deferred {
+ "promise": Promise {},
+ "reject": [Function anonymous],
+ "resolve": [Function anonymous],
+ },
+ "op": [Function anonymous],
+ "removalCallback": [Function anonymous],
+ "targetTimeMs": 1579867383588,
+ "then": [Function bound then],
+ "timerHandle": Timeout {
+ "_destroyed": false,
+ "_idleNext": TimersList {
+ "_idleNext": [Circular],
+ "_idlePrev": [Circular],
+ "expiry": 79350,
+ "id": -9007199254740987,
+ "msecs": 60000,
+ "priorityQueuePosition": 1,
+ },
+ "_idlePrev": TimersList {
+ "_idleNext": [Circular],
+ "_idlePrev": [Circular],
+ "expiry": 79350,
+ "id": -9007199254740987,
+ "msecs": 60000,
+ "priorityQueuePosition": 1,
+ },
+ "_idleStart": 19350,
+ "_idleTimeout": 60000,
+ "_onTimeout": [Function anonymous],
+ "_repeat": null,
+ "_timerArgs": undefined,
+ Symbol(refed): true,
+ Symbol(asyncId): 152,
+ Symbol(triggerId): 0,
+ },
+ "timerId": "write_stream_idle",
+ },
+ ],
+ "failure": null,
+ "operationInProgress": true,
+ "tail": Promise {},
+ "timerIdsToSkip": Array [],
+ },
+ "serializer": JsonProtoSerializer {
+ "databaseId": DatabaseId {
+ "database": "(default)",
+ "projectId": "testproject",
+ },
+ "options": Object {
+ "useProto3Json": false,
+ },
+ },
+ "state": 2,
+ "stream": StreamBridge {
+ "closeFn": [Function closeFn],
+ "sendFn": [Function sendFn],
+ "wrappedOnClose": [Function anonymous],
+ "wrappedOnMessage": [Function anonymous],
+ "wrappedOnOpen": [Function anonymous],
+ },
+ },
+ },
+ "sharedClientState": MemorySharedClientState {
+ "localState": LocalClientState {
+ "activeTargetIds": SortedSet {
+ "comparator": [Function primitiveComparator],
+ "data": SortedMap {
+ "comparator": [Function primitiveComparator],
+ "root": LLRBEmptyNode {
+ "size": 0,
+ },
+ },
+ },
+ },
+ "onlineStateHandler": [Function sharedClientStateOnlineStateChangedHandler],
+ "queryState": Object {
+ "2": "current",
+ },
+ "sequenceNumberHandler": null,
+ "syncEngine": [Circular],
+ },
+ "syncEngineListener": EventManager {
+ "onlineState": 1,
+ "queries": ObjectMap {
+ "inner": Object {},
+ "mapKeyFn": [Function anonymous],
+ },
+ "snapshotsInSyncListeners": Set {},
+ "syncEngine": [Circular],
+ },
+ },
+ },
+ "_persistenceKey": "app-1579867322226-0.11944467708511985",
+ "_queue": AsyncQueue {
+ "_isShuttingDown": false,
+ "delayedOperations": Array [
+ DelayedOperation {
+ "asyncQueue": [Circular],
+ "catch": [Function bound catch],
+ "deferred": Deferred {
+ "promise": Promise {},
+ "reject": [Function anonymous],
+ "resolve": [Function anonymous],
+ },
+ "op": [Function anonymous],
+ "removalCallback": [Function anonymous],
+ "targetTimeMs": 1579867383588,
+ "then": [Function bound then],
+ "timerHandle": Timeout {
+ "_destroyed": false,
+ "_idleNext": TimersList {
+ "_idleNext": [Circular],
+ "_idlePrev": [Circular],
+ "expiry": 79350,
+ "id": -9007199254740987,
+ "msecs": 60000,
+ "priorityQueuePosition": 1,
+ },
+ "_idlePrev": TimersList {
+ "_idleNext": [Circular],
+ "_idlePrev": [Circular],
+ "expiry": 79350,
+ "id": -9007199254740987,
+ "msecs": 60000,
+ "priorityQueuePosition": 1,
+ },
+ "_idleStart": 19350,
+ "_idleTimeout": 60000,
+ "_onTimeout": [Function anonymous],
+ "_repeat": null,
+ "_timerArgs": undefined,
+ Symbol(refed): true,
+ Symbol(asyncId): 152,
+ Symbol(triggerId): 0,
+ },
+ "timerId": "write_stream_idle",
+ },
+ ],
+ "failure": null,
+ "operationInProgress": true,
+ "tail": Promise {},
+ "timerIdsToSkip": Array [],
+ },
+ "_settings": FirestoreSettings {
+ "cacheSizeBytes": 41943040,
+ "credentials": undefined,
+ "forceLongPolling": false,
+ "host": "localhost:8080",
+ "ssl": false,
+ "timestampsInSnapshots": true,
+ },
+ },
+ "_fromCache": false,
+ "_hasPendingWrites": false,
+ "_key": DocumentKey {
+ "path": ResourcePath {
+ "len": 2,
+ "offset": 0,
+ "segments": Array [
+ "globalRule",
+ "YaGhEFEv3kFI0uUWWsSQ",
+ ],
+ },
+ },
// text turns from red to white exactly here (including } )
}
at /home/owner/PhpstormProjects/shopify/buyUsedServer/functions/src/classes/__tests__/FirestoreConnection.test.ts:73:27
at step (/home/owner/PhpstormProjects/shopify/buyUsedServer/functions/src/classes/__tests__/FirestoreConnection.test.ts:33:23)
at Object.next (/home/owner/PhpstormProjects/shopify/buyUsedServer/functions/src/classes/__tests__/FirestoreConnection.test.ts:14:53)
at fulfilled (/home/owner/PhpstormProjects/shopify/buyUsedServer/functions/src/classes/__tests__/FirestoreConnection.test.ts:5:58) {
matcherResult: {
actual: DocumentSnapshot {
_firestore: [Firestore],
_key: [DocumentKey],
_document: [Document],
_fromCache: false,
_hasPendingWrites: false,
_converter: undefined
},
expected: { storeId: 'dummystoreid', globalPercent: 40, badProp: 0 },
message: [Function],
name: 'toEqual',
pass: false
}
} =====error test("creates new record"=====
Can anyone tell what is causing the catch to return an error here? The lack of error message is making this hard to debug for me.
A couple things stand out to me in your addDocument() method:
You are first adding the document, then immediately performing a get() on the document. This will needlessly trigger a database read to pull down the same information you just provided.
That get() returns a DocumentSnapshot which is a container object for a Firestore document value. Printing out its raw contents probably includes all kinds of things you don't want.
Your test isn't really testing any of your own logic, it's essentially testing the Firestore SDK (which is already quite well tested!). What you might want is to return a data object with the Firestore Document ID inserted into it. That might look something like this:
async function addDocument(collectionName: string, documentData: object): Promise<object|null> {
try {
const newDocRef = await this.database
.collection(collectionName)
.add(documentData);
return Object.assign({}, documentData, {
__id__: newDocRef.id
});
}
catch (e) {
console.log(e, `=====error addDocument()=====`);
return null;
}
}
Then you can write a test to make sure that the resulting object has a __id__ field set.
I have the following data structure that I'm looking to transform. The structure exist as follows:
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"providers": [
{
"providerNumber": "157833AC",
"providerName": "DR TEST"
}
],
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "First Assessment",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "Consult One",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
}
I'm wanting a query that returns the id, practiceId and extrasCoverservices (serviceTypeName, serviceTypeCode and the serviceItems). I don't want to include the provider information.
I've tried this, but I need to specify the position of the element in the array which I don't want to do. Any help would be much appreciated.
SELECT a.id
, a.practiceId
, [{"serviceTypeName": a.extrasCoverServices[0].serviceTypeName, "serviceTypeCode": a.extrasCoverServices[0].serviceTypeCode, "serviceItems": a.extrasCoverServices[0].serviceItems}]
Update
function sample(documentId) {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT ARRAY_CONCAT([{"itemId": s.itemId, "itemName": s.itemName,"itemNumber":s.itemNumber,"fee":s.fee,"isReferenceItem":s.isReferenceItem}], IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices FROM a JOIN e in a.extrasCoverServices JOIN s in e.serviceItems WHERE a.id =' + "'" + documentId + "'",
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
console.log(feed.length);
var result = feed.flatten(function(x) {
return x.extrasCoverServices;
});
getContext().getResponse().setBody(result);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
You almost had it. To achieve this, you can use features:
inner-document joining using join keyword
explicit JSON composition using { and } wrappers
The first gives you access to the subItem you want to cherry-pick and the second enables you to glue them back together they way you like it.
The query you are looking for should be along the lines of this:
SELECT
a.id,
a.practiceId,
[{
"serviceTypeName": e.serviceTypeName,
"serviceTypeCode" : e.serviceTypeCode,
"serviceItems": e.serviceItems
}] as extrasCoverServices
FROM a
join e in a.extrasCoverServices
Note that you can combine Sql-like select with explicit JSON building in the same query to keep the query more compact. Also, I suggest you use CosmosDB SQL query cheat sheet to easily discover, what's in the toolbox.
function sample(documentId, itemId) {
var collection = getContext().getCollection();
var query = 'SELECT e.serviceTypeCode, '+
' e.serviceTypeName, '+
' s.itemNumber, '+
' ARRAY_CONCAT( '+
' [{ '+
' "itemId": s.itemId, '+
' "itemName": s.itemName, '+
' "fee":s.fee, '+
' "isReferenceItem":s.isReferenceItem '+
' }], '+
' IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices '+
' FROM a '+
' JOIN e in a.extrasCoverServices '+
' JOIN s in e.serviceItems '+
' WHERE a.id = ' + "'" + documentId + "'";
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
var returnResult = [];
for(var i = 0; i<feed.length; i++) {
let serviceItem = feed[i];
let serviceItemsArray = feed[i].extrasCoverServices;
for(var j = 0; j < serviceItemsArray.length; j++) {
let item = serviceItemsArray[j];
let mapped = {
serviceTypeCode: serviceItem.serviceTypeCode
, serviceTypeName: serviceItem.serviceTypeName
, itemId: item.itemId
, itemName: (item.itemName ? item.itemName : item.practiceDisplayName)
, itemNumber: serviceItem.itemNumber
, fee: item.fee
, isReferenceItem: ((item.isReferenceItem && item.isReferenceItem == true) ? item.isReferenceItem: false)
, isPracticeReferenceItem: (item.isPracticeReferenceItem && item.isPracticeReferenceItem == true ? item.isPracticeReferenceItem : false)
};
returnResult.push(mapped);
}
}
if(itemId != undefined) {
var filteredReturnResult = returnResult.filter(r => r.itemId == itemId);
getContext().getResponse().setBody(filteredReturnResult);
return
}
getContext().getResponse().setBody(returnResult);
if (!isAccepted) throw new Error('The query was not accepted by the server.');
})
}
Please use sql like:
SELECT a.id,a.practiceId,e.serviceTypeName,e.serviceTypeCode,e.serviceItems
FROM a
join e in a.extrasCoverServices a
Result:
If you want to make the e.serviceTypeName,e.serviceTypeCode,e.serviceItems into an array, not parallel with id and praticeId, I suggest you using stored procedure in cosmos db.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT c.id,c.practiceId,c.extrasCoverServices FROM root c',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
var returnResult = [];
for(var i = 0;i<feed.length;i++){
var obj1 = {
id:"",
practiceId:"",
serviceArray :[]
};
obj1.id = feed[i].id;
obj1.practiceId = feed[i].practiceId;
var loopArray = feed[i].extrasCoverServices;
var serviceResult = [];
for(var j = 0;j<loopArray.length;j++){
var obj2 = {
serviceTypeName:"",
serviceTypeCode:"",
serviceItems:[] };
obj2.serviceTypeName=loopArray[j].serviceTypeName;
obj2.serviceTypeCode=loopArray[j].serviceTypeCode;
obj2.serviceItems=loopArray[j].serviceItems;
serviceResult.push(obj2);
}
obj1.serviceArray= serviceResult;
returnResult.push(obj1);
}
getContext().getResponse().setBody(returnResult);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Result:
Hope it helps you.
Update Answer 1:
For your further requirement in your comment, I test a sql for you.
SELECT
a.id,
a.practiceId,
[{
"serviceTypeName": e.serviceTypeName,
"serviceTypeCode" : e.serviceTypeCode,
"serviceItems": [
{"itemName": s.itemName,
"itemNumber":s.itemNumber,
"fee":s.fee,
"isReferenceItem":s.isReferenceItem
},
{"practiceDisplayName":c.practiceDisplayName,
"itemNumber":s.itemNumber,
"fee": c.fee,
"isPracticeReferenceItem":c.isPracticeReferenceItem
}
]
}] as extrasCoverServices
FROM a
join e in a.extrasCoverServices
join s in e.serviceItems
join c in s.customisations
However , the results have multiple items because of the join.
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "First Assessment",
"itemNumber": "100",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
}
]
},
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult One",
"itemNumber": "200",
"fee": 23.35,
"isPracticeReferenceItem": "true"
}
]
}
]
},
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"itemNumber": "200",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
So, I suggest you processing the results in the stored procedure to match your requirement.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT a.id, a.practiceId,'+
'[{'+
'"serviceTypeName": e.serviceTypeName, '+
'"serviceTypeCode" : e.serviceTypeCode, '+
'"serviceItems": ['+
'{"itemName": s.itemName,'+
'"itemNumber":s.itemNumber,'+
'"fee":s.fee,'+
'"isReferenceItem":s.isReferenceItem'+
'},'+
'{"practiceDisplayName":c.practiceDisplayName,'+
'"itemNumber":s.itemNumber,'+
'"fee": c.fee,'+
'"isPracticeReferenceItem":c.isPracticeReferenceItem '+
'}'+
']'+
'}] as extrasCoverServices'+
' FROM a '+
' join e in a.extrasCoverServices'+
' join s in e.serviceItems'+
' join c in s.customisations',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
var returnResult = [];
var obj1 = {
id:"",
practiceId:"",
extrasCoverServices :[]
};
var temp = "";
for(var i = 0;i<feed.length;i++){
if(temp==feed[i].id){
var extrasArray = obj1.extrasCoverServices[0].serviceItems;
var serviceArray = feed[i].extrasCoverServices[0].serviceItems;
for(var j = 0;j<serviceArray.length;j++){
extrasArray.push(serviceArray[j]);
}
obj1.extrasCoverServices[0].serviceItems = extrasArray;
} else{
obj1.id = feed[i].id;
obj1.practiceId = feed[i].practiceId;
obj1.extrasCoverServices = feed[i].extrasCoverServices;
temp = feed[i].id;
}
}
returnResult.push(obj1);
getContext().getResponse().setBody(returnResult);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Process Result:
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "First Assessment",
"itemNumber": "100",
"fee": 50,
"isPracticeReferenceItem": "true"
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult One",
"itemNumber": "200",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"itemNumber": "200",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
Update Answer 2:
Well,I still focus on implementing your needs through the Stored Procedure.
I add one item without customisations array into serviceItems as below:
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "First Assessment",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "Consult One",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
},
{
"itemName": "FOR TEST",
"itemNumber": "333",
"fee": 20,
"isReferenceItem": "true"
}
]
}
]
}
]
SP CODE:
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT a.id, a.practiceId,'+
'[{'+
'"serviceTypeName": e.serviceTypeName, '+
'"serviceTypeCode" : e.serviceTypeCode, '+
'"serviceItems": e.serviceItems'+
'}] as extrasCoverServices'+
' FROM a '+
' join e in a.extrasCoverServices',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
for(var i = 0;i<feed.length;i++){
var extraArray = feed[i].extrasCoverServices;
for(var j = 0;j<extraArray.length;j++){
var serviceArray = extraArray[j].serviceItems;
var array = [];
for(var k = 0;k<serviceArray.length;k++){
var o1 = {
"itemName": "",
"itemNumber":"",
"fee" : "",
"isReferenceItem":""
};
console.log(k+"----");
o1.itemName = serviceArray[k].itemName;
o1.itemNumber = serviceArray[k].itemNumber;
o1.fee = serviceArray[k].fee;
o1.isReferenceItem = serviceArray[k].isReferenceItem;
console.log(o1.itemName);
array.push(o1);
if(null != serviceArray[k].customisations){
var customisationsArray = serviceArray[k].customisations;
for(var p = 0;p<customisationsArray.length;p++){
var o2 = {
"practiceDisplayName": "",
"itemNumber":"",
"fee" : "",
"isPracticeReferenceItem":""
};
o2.practiceDisplayName = customisationsArray[p].practiceDisplayName;
o2.itemNumber = o1.itemNumber;
o2.fee = customisationsArray[p].fee;
o2.isPracticeReferenceItem = customisationsArray[p].isPracticeReferenceItem;
array.push(o2);
}
}
}
feed[i].extrasCoverServices[j].serviceItems = array;
}
}
getContext().getResponse().setBody(feed);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Just for summary, I tidied up your last SP code. This is a good thread.
function sample(documentId, itemId) {
var collection = getContext().getCollection();
var query = 'SELECT e.serviceTypeCode, '+
' e.serviceTypeName, '+
' s.itemNumber, '+
' ARRAY_CONCAT( '+
' [{ '+
' "itemId": s.itemId, '+
' "itemName": s.itemName, '+
' "fee":s.fee, '+
' "isReferenceItem":s.isReferenceItem '+
' }], '+
' IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices '+
' FROM a '+
' JOIN e in a.extrasCoverServices '+
' JOIN s in e.serviceItems '+
' WHERE a.id = ' + "'" + documentId + "'";
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
var returnResult = [];
for(var i = 0; i<feed.length; i++) {
let serviceItem = feed[i];
let serviceItemsArray = feed[i].extrasCoverServices;
for(var j = 0; j < serviceItemsArray.length; j++) {
let item = serviceItemsArray[j];
let mapped = {
serviceTypeCode: serviceItem.serviceTypeCode
, serviceTypeName: serviceItem.serviceTypeName
, itemId: item.itemId
, itemName: (item.itemName ? item.itemName : item.practiceDisplayName)
, itemNumber: serviceItem.itemNumber
, fee: item.fee
, isReferenceItem: ((item.isReferenceItem && item.isReferenceItem == true) ? item.isReferenceItem: false)
, isPracticeReferenceItem: (item.isPracticeReferenceItem && item.isPracticeReferenceItem == true ? item.isPracticeReferenceItem : false)
};
returnResult.push(mapped);
}
}
if(itemId != undefined) {
var filteredReturnResult = returnResult.filter(r => r.itemId == itemId);
getContext().getResponse().setBody(filteredReturnResult);
return
}
getContext().getResponse().setBody(returnResult);
if (!isAccepted) throw new Error('The query was not accepted by the server.');
})
}
I am trying to plot a mutibar column chart with legend. This is my code. The code is seems to be working but its not adding legend in an appropriate format. I'm adding screenshots of my data table and the output coming from my code. The legend should be showing Different types of priorities but its showing "Legend Text" everywhere.
Output
Datatable
//Plotting Matrix Chart
chartMatrix.Visible = true;
LoadChartData(dtHourvsPriorityMatrix);
chartMatrix.Series["Priority"].ChartType = SeriesChartType.Column;
chartMatrix.Series["Priority"]["DrawingStyle"] = "Emboss";
//chartMatrix.ChartAreas["ChartArea1"].Area3DStyle.Enable3D = true;
chartMatrix.Series["Priority"].IsValueShownAsLabel = true;
// Create a new legend called "Legend".
chartMatrix.Legends.Add(new Legend("Legend"));
// Set Docking of the Legend chart to the Default Chart Area.
chartMatrix.Legends["Legend"].DockedToChartArea = "ChartAreaF";
// Assign the legend to Series=Priority.
chartMatrix.Series["Priority"].Legend = "Legend";
chartMatrix.Series["Priority"].IsVisibleInLegend = true;
LegendCellColumn lcc = new LegendCellColumn("Priority", LegendCellColumnType.Text, "LEGENDTEXT");
lcc.HeaderFont = new System.Drawing.Font("Trebuchet MS", 12F, System.Drawing.FontStyle.Bold);
chartMatrix.Legends["Legend"].CellColumns.Add(lcc);
private void LoadChartData(DataTable initialDataSource)
{
for (int i = 1; i < initialDataSource.Columns.Count; i++)
{
Series series = new Series();
foreach (DataRow dr in initialDataSource.Rows)
{
int y = (int)dr[i];
series.Points.AddXY(dr["Hour"].ToString(), y);
}
chartMatrix.Series.Add(series);
}
}
Try to use canvasjs chart.
Use web service for binding data
<script type="text/javascript">
$(document).ready(function () {
var district = $('#ContentPlaceHolder1_hiddistrict').val();
var assembly = $('#ContentPlaceHolder1_hidassembly').val();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: "../WebMyVoterService.asmx/GenderWise",
data: '{"districtid":"' + district + '","assembly" :"' + assembly + '" }',
processData: false,
success: OnSuccess,
failure: function (response) {
alert(response);
},
error: function (response) {
alert(response);
}
});
function OnSuccess(response) {
var dpmale = [];
var dpfemale = [];
for (var i = 0; i < response.d.length; i++) {
var obj = response.d[i];
var datamale =
{
y: parseInt(obj.male),
label: obj.boothno,
};
var datafemale =
{
y: parseInt(obj.female),
label: obj.boothno,
};
dpmale.push(datamale);
dpfemale.push(datafemale);
}
var chart = new CanvasJS.Chart("chartContainerbar", {
animationEnabled: true,
axisX: {
interval: 1,
labelFontSize: 10,
lineThickness: 0,
},
axisY2: {
valueFormatString: "0",
lineThickness: 0,
labelFontSize: 10,
},
toolTip: {
shared: true
},
legend: {
verticalAlign: "top",
horizontalAlign: "center",
fontSize: 10,
},
data: [{
type: "stackedBar",
showInLegend: true,
name: "Male",
axisYType: "secondary",
color: "#f8d347",
dataPoints: dpmale
},
{
type: "stackedBar",
showInLegend: true,
name: "Female",
axisYType: "secondary",
color: "#6ccac9",
dataPoints: dpfemale
}
]
});
chart.render();
}
});
</script>
URL : http://canvasjs.com/
Hii Guys!!!.
I developed a Jqgrid to diaplay database.Now I want to add JQgrid filter Toolbar to refine the data as per user need so i added filter toolbar.But Filter Toolbar is working with only when 'loadonce:true' means locally with first page data whereas I want it to work for whole database...from server response...
Below I am posting my code for refrence ...
$(function () {
$("#UsersGrid").jqGrid({
url: 'getGriddahico.ashx',
datatype: 'json',
height: 250,
colNames: ['UserID', 'username', 'ordinal', 'authcode', 'extension', 'trunk', 'dialnumber', 'dialdate', 'dialtime', 'duration', 'destination', 'price', 'toc'],
colModel: [
{ name: 'UserID', index: 'UserID', width: 100, sortable: true, align: 'center',hidden:true },
{ name: 'username', width: 100, sortable: true, align: 'center' },
{ name: 'ordinal', width: 100, sortable: true, align: 'center' },
{ name: 'authcode', width: 100, sortable: true },
{ name: 'extension', width: 100, sortable: true, align: 'center' },
{ name: 'trunk', width: 100, sortable: true, align: 'center' },
{ name: 'dialnumber', width: 100, sortable: true, align: 'center' },
{ name: 'dialdate', width: 100, sortable: true, align: 'center' },
{ name: 'dialtime', width: 100, sortable: true, align: 'center' },
{ name: 'duration', width: 100, sortable: true, align: 'center' },
{ name: 'destination', width: 100, sortable: true, align: 'center' },
{ name: 'price', width: 100, sortable: true, align: 'center' },
{ name: 'toc', width: 150, sortable: true, align: 'center' }
],
rowNum: 100,
rowList: [100, 200, 300],
pager: '#UsersGridPager',
sortname: 'username',
//loadonce: true,
viewrecords: true,
ignoreCase:true,
sortorder: 'asc',
autowidth: true,
toppager: true,
height: '100%'
});
$("#UsersGrid").jqGrid('navGrid', '#UsersGridPager', { edit: false, add: false, del: false, search: false });
jQuery("#UsersGrid").jqGrid('filterToolbar', { stringResult: true, searchOnEnter: false });
});
My Handler(.ashx) file code:
int start=0;
int total=0;
int total_pages =0;
int intpage =Convert.ToInt32(request["page"]);
int limit=Convert.ToInt32(request["rows"]);
// int intpage = new Integer(request.getParameter("page"));
//int limit = new Integer(request.getParameter("rows"));
string sidx = request["sidx"];
string sord = request["sord"];
// String sidx = request.getParameter("sidx");
//String sord = request.getParameter("sord");
String strQuery="";
String json ="";
Boolean rc ;
MySqlDataReader rs;
//ResultSet rs = null;
if(sidx ==""){
sidx ="1";
}
/*-----------------------------------Conexión a la base de datos MySql-------------------------------------------*/
conexion conexiondb = new conexion();
conexiondb.Conectar();
/*-----------------------------------------------------------------------------------------------------------*/
total = conexiondb.countRec("price", "processeddata_table");
if( total>0 ) {
double d = Math.Ceiling( (double)(total) / (double)(limit) );
total_pages = (int)(d);
} else {
total_pages = 0;
}
if (intpage > total_pages) {
intpage=total_pages;
}
start = limit * intpage - limit;
if(start < 0 ){
start = 0;
}
//strQuery = "SELECT username,ordinal,authcode,extension,trunk,dialnumber,dialdate,dialtime,duration,destination,price,toc FROM processeddata_table ORDER BY username asc";
strQuery = "SELECT username,ordinal,authcode,extension,trunk,dialnumber,dialdate,dialtime,duration,destination,price,toc FROM processeddata_table ORDER BY " + sidx + " " + sord + " LIMIT " + start + " , " + limit;
rs = conexiondb.Consulta(strQuery);
total = conexiondb.countRec("price", "processeddata_table");
response.ContentType="text/x-json";
response.ContentType = "charset=utf-8";
//response.ContentEncoding="utf-8";
response.AddHeader("Pragma", "no-cache");
response.AddHeader("Cache-Control", "no-cache, must-revalidate");
response.AddHeader("Pragma", "no-cache");
json ="";
json = json + "{\n";
json = json + " \"page\":\""+intpage+"\",\n";
json = json + "\"total\":"+total_pages+",\n";
json = json + "\"records\":"+total+",\n";
json = json + "\"rows\": [";
rc =false;
while(rs.Read()){
if(rc){
json = json + ",";
}
json = json + "\n{";
json = json + "\"price\":\"" + Convert.ToInt32(rs["price"]) + "\",";
json = json + "\"cell\":[" + Convert.ToInt32(rs["price"]) + "";
json = json + ",\"" + Convert.ToString(rs["username"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["ordinal"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["authcode"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["extension"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["trunk"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["dialnumber"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["dialdate"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["dialtime"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["duration"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["destination"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["price"]) + "\"";
json = json + ",\"" + Convert.ToString(rs["toc"]) + "\"]";
json = json + "}";
rc=true;
}
json = json +"]\n";
json = json +"}";
HttpContext.Current.Response.Write(json);
Plz guys help me to resolve the issue..
Thanx in advance..
If you use loadonce: true option then the data will be loaded from the server at once and later searching, sorting and paging of the previously loaded data will be implemented locally by jqGrid.
If you don't want to use loadonce: true option then you have to implement the features in your server code. In the answer for example you can find an example of such implementation in the code which uses ASHX like you do.