From 7f8875018466a08f399e1a738df615d2c84f4beb Mon Sep 17 00:00:00 2001 From: chin Date: Fri, 4 Nov 2022 23:02:01 +0800 Subject: [PATCH] feat: use jsonpath, countDocuments - Use jsonpath instead of searching reference field > Fix the problem with `reference.reference` field cannot parse > For better coding way - Remove `checkReference` in apiService > unused - Use countDocuments instead of findOne for better performance > findOne will return full document when exist > we just need to check document is exist > countDocuments may faster --- api/apiService.js | 122 ++++-------------- .../middleware/checkReference.js | 19 +-- 2 files changed, 31 insertions(+), 110 deletions(-) diff --git a/api/apiService.js b/api/apiService.js index 59f54c7..087af7e 100644 --- a/api/apiService.js +++ b/api/apiService.js @@ -51,109 +51,35 @@ async function findResourceById(resource, id) { } } -async function checkReference(resourceData) { - let checkedReferenceList = []; - let resourceDeepKeys = getDeepKeys(resourceData); - let referenceKeys = resourceDeepKeys.filter( - v => v.endsWith(".reference") - ); - for (let key of referenceKeys) { - let referenceValue = _.get(resourceData, key); - let referenceValueSplit = referenceValue.split('|')[0].split('/'); - if (/^(http|https):\/\//g.test(referenceValue)) { - //do fetch to get response - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 1268 + 1231); - try { - let fetchRes = await fetch(referenceValue, { - headers: { - accept: "application/fhir+json" - } , - signal: controller.signal - }); - if (fetchRes.status == 200) { - let referenceJson = await fetchRes.json(); - let fhir = new FHIR(); - if (fhir.validate(referenceJson).valid) { - checkedReferenceList.push({ - exist: true, - path: key, - value: referenceValue - }); - } else { - checkedReferenceList.push({ - exist: false, - path: key, - value: referenceValue - }); - } - } else { - checkedReferenceList.push({ - exist: false, - path: key, - value: referenceValue - }); - } - } catch (e) { - checkedReferenceList.push({ - exist: false, - path: key, - value: referenceValue - }); - } finally { - clearTimeout(timeoutId); - } - } else if (referenceValueSplit.length >= 2) { - let resourceName = referenceValueSplit[referenceValueSplit.length - 2]; - let resourceId = referenceValueSplit[referenceValueSplit.length - 1]; - let doc = await findResourceById(resourceName, resourceId); - if (doc) { - checkedReferenceList.push({ - exist: true, - path: key, - value: referenceValue - }); - } else { - checkedReferenceList.push({ - exist: false, - path: key, - value: referenceValue - }); - } - } else if (/urn:oid:[0-2](\.[1-9]\d*)+/i.test(referenceValue) || - /^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(referenceValue)) { - //Only Bundle entry have OID or UUID reference? - let referenceTargetFullUrl = resourceDeepKeys.find( - v => _.get(resourceData, v) == referenceValue && - v.endsWith("fullUrl") - ); - if (referenceTargetFullUrl) { - checkedReferenceList.push({ - exist: true, - path: key, - value: referenceValue - }); - } else { - checkedReferenceList.push({ - exist: false, - path: key, - value: referenceValue - }); - } +/** + * + * @param {string} id The resource id + * @param {string} resourceType Resource type + * @returns status: 1 mean "exist", 2 mean "not exist", 0 mean "another error" + */ +async function isDocExist(id, resourceType) { + try { + let data = await mongodb[resourceType].countDocuments({id: id}).limit(1); + if (data > 0) { + return { + status: 1, + error: "" + }; } - } - if (checkedReferenceList.length > 0) { return { - status : checkedReferenceList.every(v=> v.exist), - checkedReferenceList: checkedReferenceList + status: 2, + error: "" + }; + } catch(e) { + console.error(e); + return { + status: 0, + error: e }; } - return { - status: true, - checkedReferenceList: checkedReferenceList - }; } + function getNotExistReferenceList(checkReferenceRes) { let notExistReferenceList = []; for (let reference of checkReferenceRes.checkedReferenceList) { @@ -187,7 +113,7 @@ module.exports = { getDeepKeys: getDeepKeys, isRealObject: isRealObject, findResourceById: findResourceById, - checkReference: checkReference , + isDocExist: isDocExist, getNotExistReferenceList: getNotExistReferenceList, renameCollectionFieldName: renameCollectionFieldName }; \ No newline at end of file diff --git a/plugins/checkReference/middleware/checkReference.js b/plugins/checkReference/middleware/checkReference.js index 4e292b0..0148a19 100644 --- a/plugins/checkReference/middleware/checkReference.js +++ b/plugins/checkReference/middleware/checkReference.js @@ -5,7 +5,8 @@ const { handleError } = require('../../../models/FHIR/httpMessage'); const FHIR = require("fhir").Fhir; -const { getDeepKeys, findResourceById } = require("../../../api/apiService"); +const { isDocExist } = require("../../../api/apiService"); +const jp = require("jsonpath"); async function checkAbsoluteUrlRef(key, referenceValue, checkedReferenceList) { //do fetch to get response @@ -54,11 +55,8 @@ async function checkAbsoluteUrlRef(key, referenceValue, checkedReferenceList) { async function checkReference(resourceData) { let checkedReferenceList = []; - let resourceDeepKeys = getDeepKeys(resourceData); - let referenceKeys = resourceDeepKeys.filter( - v => v.endsWith(".reference") - ); - for (let key of referenceKeys) { + let referenceKeysJp = jp.paths(resourceData, "$..reference").map( v=> v.join(".").substring(2)); + for (let key of referenceKeysJp) { let referenceValue = _.get(resourceData, key); let referenceValueSplit = referenceValue.split('|')[0].split('/'); if (/^(http|https):\/\//g.test(referenceValue)) { @@ -66,8 +64,8 @@ async function checkReference(resourceData) { } else if (referenceValueSplit.length >= 2) { let resourceName = referenceValueSplit[referenceValueSplit.length - 2]; let resourceId = referenceValueSplit[referenceValueSplit.length - 1]; - let doc = await findResourceById(resourceName, resourceId); - if (doc) { + let doc = await isDocExist(resourceId, resourceName); + if (doc.status === 1) { checkedReferenceList.push({ exist: true, path: key, @@ -83,10 +81,7 @@ async function checkReference(resourceData) { } else if (/urn:oid:[0-2](\.[1-9]\d*)+/i.test(referenceValue) || /^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(referenceValue)) { //Only Bundle entry have OID or UUID reference? - let referenceTargetFullUrl = resourceDeepKeys.find( - v => _.get(resourceData, v) == referenceValue && - v.endsWith("fullUrl") - ); + let referenceTargetFullUrl = jp.nodes(resourceData, "$..fullUrl").find( v=> v.value === referenceValue); if (referenceTargetFullUrl) { checkedReferenceList.push({ exist: true,