Micro-FrontEnd with jsGrid & MongoDB

Micro-FrontEnd with jsGrid & MongoDB
Photo by Rubaitul Azad / Unsplash

This flow uses the html template and js-grid to display, create, remove, update and delete data rows.

flow

in Ubuntu

~\.node-red\settings.js

include the ObjectId as global import

functionGlobalContext: {
        require: require, // Not mandatory
        ObjectId : require('mongodb').ObjectID,
},

And inside the function node, I just passed the payload as follows.

var ObjectId = global.get('ObjectId');

msg.payload={
    "_id":ObjectId("5c9156c7f8c3ec3259454571")
};

return msg;

flows.json

[{"id":"0338c3befa10e3ef","type":"tab","label":"MongoDB","disabled":false,"info":"","env":[]},{"id":"c93ad5d5e0bf09e5","type":"tab","label":"MySQL","disabled":true,"info":"","env":[]},{"id":"bad1ea5a333cb4d4","type":"tab","label":"Memory","disabled":true,"info":"","env":[]},{"id":"dc42e32dff073243","type":"group","z":"0338c3befa10e3ef","name":"","style":{"fill":"#bfbfbf","label":true},"nodes":["98bb4419b579a05d","a44dccd094937dc7","0214f907c6dde6e5","6830fb5b2dbb3c58","11de8e1f4cb16d24","037dce8e31058aab"],"x":28,"y":33,"w":1304,"h":534},{"id":"b63843cb893f8f99","type":"group","z":"bad1ea5a333cb4d4","style":{"stroke":"#93a1a1","stroke-opacity":"1","fill":"#eee8d5","fill-opacity":"0.5","label":true,"label-position":"nw","color":"#657b83"},"nodes":["33f215417669f302","2bb822373b452b47","ad333172fb04b7e2","4a491b95e245e7c2","9f33e072997368b6","577d77dde821fe0e","2a45b1abb1a49ad6","305b5d0d4c97d4dd","098469ab1a800fe3","04955bf65de9fe2f","6445eb497e758dcc","55b62a42ae2ad47c","849df9bee5b7e1c5","16d491dfbd02964e","70a0e93542650b1f","7aea695d8fc1488c","8cea908331c72a07"],"x":34,"y":39},{"id":"7b144e46f5b6ec43","type":"group","z":"c93ad5d5e0bf09e5","style":{"stroke":"#93a1a1","stroke-opacity":"1","fill":"#eee8d5","fill-opacity":"0.5","label":true,"label-position":"nw","color":"#657b83"},"nodes":["d433feb1.6365e","98b6cece.37871","3c1830eb.33b9","ef285826.0e9738","e396f56a.dcda38","458b0528.a4d98c","d84f16f7.3d9698","2b952c3a.f63884","c91568f0.c3f2f8","e4b82091.b8e9a","81bb8cdf.93e5b","c224cbcf.e3e718","9929a22b.66471","4bfc0ef6.e8511","c70c0833.831ab8","f92b07.fa8e84f8","7b9f8d8b.c6d4e4","857ff60c.da9078","9a8b3fa.c0817c","5b19502.0bae0b","4520409.a2751c","b9aef47c.8f0938","ece93a93.ebc878","930f03c1.94bd5","e51fe384.1db73","9fe2ed80.2522c","6ce2248e.9c889c","50307401.f1297c","c1934c38.6647d","973e8aa6.834338"],"x":34,"y":19},{"id":"98bb4419b579a05d","type":"group","z":"0338c3befa10e3ef","g":"dc42e32dff073243","name":"","style":{"stroke":"#61AFFE","label":true,"fill":"#EFF7FF","fill-opacity":"1"},"nodes":["1cb547dae9f9416d","117569d4e15e635d","6793251b39be4255","032c5b5f76bb58ec","38ebb2b60b411e67"],"x":54,"y":159,"w":1252,"h":82},{"id":"a44dccd094937dc7","type":"group","z":"0338c3befa10e3ef","g":"dc42e32dff073243","name":"","style":{"fill":"#FFF5EA","label":true,"fill-opacity":"1","stroke":"#FCA130"},"nodes":["e12ffb8302454083","f9e42c50a8fc1816","9f069642444c25a7","0f538eeddd4f4270","377e6144780b155c"],"x":54,"y":259,"w":1252,"h":82},{"id":"0214f907c6dde6e5","type":"group","z":"0338c3befa10e3ef","g":"dc42e32dff073243","name":"","style":{"fill":"#ECFAF4","fill-opacity":"1","label":true,"stroke":"#49CC90"},"nodes":["25538d080ca6636d","6fa3df0a02c2e2d7","c266861c547ad94b","df1b7b5834c6cb38"],"x":54,"y":359,"w":1252,"h":82},{"id":"6830fb5b2dbb3c58","type":"group","z":"0338c3befa10e3ef","g":"dc42e32dff073243","name":"","style":{"fill":"#FFEBEB","fill-opacity":"1","label":true,"stroke":"#F93E3E"},"nodes":["f60209089e073bc6","75d1256bb4f79751","8731432811f95b1a","3d4e6c7b4de7bac6"],"x":54,"y":459,"w":1252,"h":82},{"id":"11de8e1f4cb16d24","type":"group","z":"0338c3befa10e3ef","g":"dc42e32dff073243","name":"","style":{"fill":"#FDF6E3","fill-opacity":"1","label":true},"nodes":["cc207b5b.33df88","1d1b40c4d0f7ee32","c2852efd.3d7ad","663e1cfb.99c1e4","5fd8010a154e7b55"],"x":154,"y":59,"w":1152,"h":82},{"id":"f6c122ad.621c98","type":"mongodb2","uri":"mongodb://localhost:27017/db","name":"db","options":"","parallelism":"-1"},{"id":"d48d08d1.d221d8","type":"MySQLdatabase","name":"","host":"localhost","port":"3306","db":"mysql","tz":"","charset":""},{"id":"377e6144780b155c","type":"http in","z":"0338c3befa10e3ef","g":"a44dccd094937dc7","name":"","url":"/update","method":"put","swaggerDoc":"","x":150,"y":300,"wires":[["0f538eeddd4f4270"]]},{"id":"f9e42c50a8fc1816","type":"mongodb2 in","z":"0338c3befa10e3ef","g":"a44dccd094937dc7","service":"_ext_","configNode":"f6c122ad.621c98","name":"","collection":"LicencePlate","operation":"update","x":690,"y":300,"wires":[["e12ffb8302454083"]]},{"id":"9f069642444c25a7","type":"http response","z":"0338c3befa10e3ef","g":"a44dccd094937dc7","name":"","x":1230,"y":300,"wires":[]},{"id":"0f538eeddd4f4270","type":"function","z":"0338c3befa10e3ef","g":"a44dccd094937dc7","name":"update request","func":"/*\nmsg.result correspond à l'objet mis à jour,\nle delete permet de supprimer la propriété\n_id de l'objet, en effet l'_id est géré directement\npar le noued OjectId\npour la requète update  \non doit fournir un tableau \n[\n<query>,\n<valeur mises à jour>\n]\n\nici ce sera de la forme:\n[\n    {_id:ObjectId(\"xxx\")},\n    {\"nom\": \"toto\", \"prenom\": \"tutu\", \n        \"immatriculation\": \"AB123CD\", \n        \"heure\": null, \"minute\": null\n    }\n]\n*/\nvar ObjectId = global.get('ObjectId');\nmsg.payload = {\n    \"_id\": ObjectId(msg.payload._id)\n};\n\nmsg.result=msg.req.body;\ndelete msg.req.body._id;\n\nmsg.payload=[\n   msg.payload,\n   msg.req.body\n];\nreturn msg;\n\n","outputs":"1","noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":300,"wires":[["f9e42c50a8fc1816"]]},{"id":"032c5b5f76bb58ec","type":"http in","z":"0338c3befa10e3ef","g":"98bb4419b579a05d","name":"","url":"/index","method":"get","upload":false,"swaggerDoc":"","x":140,"y":200,"wires":[["6793251b39be4255"]]},{"id":"117569d4e15e635d","type":"http response","z":"0338c3befa10e3ef","g":"98bb4419b579a05d","name":"","x":1230,"y":200,"wires":[]},{"id":"6793251b39be4255","type":"mongodb2 in","z":"0338c3befa10e3ef","g":"98bb4419b579a05d","service":"_ext_","configNode":"f6c122ad.621c98","name":"","collection":"LicencePlate","operation":"find.toArray","x":440,"y":200,"wires":[["1cb547dae9f9416d"]]},{"id":"1cb547dae9f9416d","type":"json","z":"0338c3befa10e3ef","g":"98bb4419b579a05d","name":"","x":750,"y":200,"wires":[["38ebb2b60b411e67"]]},{"id":"e12ffb8302454083","type":"function","z":"0338c3befa10e3ef","g":"a44dccd094937dc7","name":"callback response","func":"/*\npour que la jsGrid soit rafraichie, \nil faut lui envoyer l'objet qui a été mis à jour\n*/\nmsg.payload=msg.result;\nreturn msg;","outputs":1,"noerr":0,"x":1010,"y":300,"wires":[["9f069642444c25a7"]]},{"id":"6fa3df0a02c2e2d7","type":"mongodb2 in","z":"0338c3befa10e3ef","g":"0214f907c6dde6e5","service":"_ext_","configNode":"f6c122ad.621c98","name":"","collection":"LicencePlate","operation":"insert","x":420,"y":400,"wires":[["25538d080ca6636d"]]},{"id":"c266861c547ad94b","type":"http response","z":"0338c3befa10e3ef","g":"0214f907c6dde6e5","name":"","x":1230,"y":400,"wires":[]},{"id":"df1b7b5834c6cb38","type":"http in","z":"0338c3befa10e3ef","g":"0214f907c6dde6e5","name":"","url":"/insert","method":"post","swaggerDoc":"","x":150,"y":400,"wires":[["6fa3df0a02c2e2d7"]]},{"id":"3d4e6c7b4de7bac6","type":"http in","z":"0338c3befa10e3ef","g":"6830fb5b2dbb3c58","name":"","url":"/delete","method":"delete","swaggerDoc":"","x":160,"y":500,"wires":[["75d1256bb4f79751"]]},{"id":"f60209089e073bc6","type":"mongodb2 in","z":"0338c3befa10e3ef","g":"6830fb5b2dbb3c58","service":"_ext_","configNode":"f6c122ad.621c98","name":"","collection":"LicencePlate","operation":"deleteOne","x":880,"y":500,"wires":[["8731432811f95b1a"]]},{"id":"8731432811f95b1a","type":"http response","z":"0338c3befa10e3ef","g":"6830fb5b2dbb3c58","name":"","x":1230,"y":500,"wires":[]},{"id":"25538d080ca6636d","type":"function","z":"0338c3befa10e3ef","g":"0214f907c6dde6e5","name":"callback response","func":"/*\npour que la jsGrid soit rafraichie, \nil faut lui envoyer l'objet qui a été mis à jour\n*/\nmsg.payload=msg.req.body;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":400,"wires":[["c266861c547ad94b"]]},{"id":"75d1256bb4f79751","type":"function","z":"0338c3befa10e3ef","g":"6830fb5b2dbb3c58","name":"extract _id","func":"var ObjectId = global.get('ObjectId');\nmsg.payload = {\n    \"_id\": ObjectId(msg.payload._id)\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":500,"wires":[["f60209089e073bc6"]]},{"id":"663e1cfb.99c1e4","type":"function","z":"0338c3befa10e3ef","g":"11de8e1f4cb16d24","name":"split elements","func":"var mapResult = {\n  countdown: msg.payload.length,\n  result: msg.payload.map(function(){})\n};\nreturn [msg.payload.map(function(element, index) {\n  return {\n    payload: element,\n    index: index,\n    mapResult: function() {\n      return mapResult;\n    }\n  };\n})];\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":100,"wires":[["1d1b40c4d0f7ee32"]],"icon":"node-red/split.svg"},{"id":"cc207b5b.33df88","type":"function","z":"0338c3befa10e3ef","g":"11de8e1f4cb16d24","name":"reconstruct array","func":"var mapResult = msg.mapResult();\nmapResult.result[msg.index] = msg.payload;\nmapResult.countdown -= 1;\nif (0 === mapResult.countdown) {\n  return {\n    payload: mapResult.result\n  };\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1070,"y":100,"wires":[["c2852efd.3d7ad"]],"icon":"node-red/join.svg"},{"id":"c2852efd.3d7ad","type":"debug","z":"0338c3befa10e3ef","g":"11de8e1f4cb16d24","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1245,"y":100,"wires":[],"l":false},{"id":"5fd8010a154e7b55","type":"function","z":"0338c3befa10e3ef","g":"11de8e1f4cb16d24","name":"Generate dummy data","func":"const firstNames =  [\"Liam\",\"Noah\",\"Oliver\",\"William\",\"Elijah\",\"James\",\"Benjamin\",\"Lucas\",\"Mason\",\"Ethan\",\"Alexander\",\"Henry\",\"Jacob\",\"Michael\",\"Daniel\",\"Logan\",\"Jackson\",\"Sebastian\",\"Jack\",\"Aiden\"];\nconst sirNames = [\"Jones\",\"Taylor\",\"Williams\",\"Brown\",\"White\",\"Harris\",\"Martin\",\"Davies\",\"Wilson\",\"Cooper\",\"Evans\",\"King\",\"Thomas\",\"Baker\",\"Green\",\"Wright\",\"Johnson\",\"Edwards\",\"Clark\",\"Roberts\",\"Robinson\",\"Hall\",\"Lewis\",\"Young\",\"Davis\",\"Turner\",\"Hill\",\"Phillips\",\"Collins\",\"Allen\",\"Moore\",\"Thompson\",\"Carter\",\"James\",\"Knight\",\"Walker\",\"Wood\",\"Hughes\",\"Parker\",\"Ward\",\"Bennett\",\"Cook\",\"Webb\",\"Bailey\",\"Scott\",\"Jackson\",\"Lee\",\"Cox\"];\n         \n         \n\nvar database = [];\n\nfor(let i = 1; i <= 30; i++) {\n    var item = {\"id\":i, \"timestamp\":Date.now()};\n    item.foreName = randomFirstname();\n    item.sirName = randomSirname();\n    item.userID = \"U\" + randomInt(1000, 2999);\n    item.age = randomInt(20, 65);\n    database.push(item);\n}\n\n\nfunction randomFirstname() {\n   return firstNames[randomInt(0, firstNames.length-1)];\n}\n\nfunction randomSirname() {\n    return sirNames[randomInt(0, sirNames.length-1)];\n}\n\nfunction randomInt(min, max) { \n  return Math.floor(Math.random() * (max - min + 1) + min);\n}\n\nflow.set(\"database\", database);\nmsg.payload = database;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":100,"wires":[["663e1cfb.99c1e4"]],"icon":"node-red/leveldb.png"},{"id":"1d1b40c4d0f7ee32","type":"mongodb2 in","z":"0338c3befa10e3ef","g":"11de8e1f4cb16d24","service":"_ext_","configNode":"f6c122ad.621c98","name":"","collection":"LicencePlate","operation":"insert","x":800,"y":100,"wires":[["cc207b5b.33df88"]]},{"id":"38ebb2b60b411e67","type":"template","z":"0338c3befa10e3ef","g":"98bb4419b579a05d","name":"Web Template","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html lang=\"en-GB\">\n<head>\n    <title>Users</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/bootstrap-timepicker/0.5.2/css/bootstrap-timepicker.min.css\" />\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js\"></script>\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.css\" />\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid-theme.min.css\" />\n    <script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.js\"></script>\n\n    <script type=\"text/javascript\">\n        $(function () {\n            console.log(\"crud demo\");\n\n            var db = {{#payload}}{{{.}}}{{/payload}};\n\n            $(\"#jsgrid\").jsGrid({\n                width: \"100%\",\n                    confirmDeleting: false,\n                    inserting: true,\n                    editing: true,\n                    sorting: true,\n                    paging: true,\n\n                data: db,\n\n                fields: [\n                    { title:\"ID\", name: \"id\", type: \"number\", width: 20, readOnly: true },\n                    { title:\"User ID\", name: \"userID\", type: \"text\", width: 50 },\n                    { title:\"First Name\", name: \"foreName\", type: \"text\", width: 50 },\n                    { title:\"Last Name\", name: \"sirName\", type: \"text\", width: 50 },\n                    { title:\"Age\", name: \"age\", type:\"number\", width: 25},\n                    { type: \"control\" }\n                ],\n           \n                controller: {\n                    insertItem: function(item) {\n                        return $.ajax({\n                            type: \"POST\",\n                            url: \"/insert\",\n                            data: item\n                        });\n                    },\n                    updateItem: function(item) {\n                       return $.ajax({\n                            type: \"PUT\",\n                            url: \"/update\",\n                            data: item\n                        });\n                    },\n                    deleteItem: function(item) {\n                        return $.ajax({\n                            type: \"DELETE\",\n                            url: \"/delete\",\n                            data: item\n                        });\n                    }\n                }   \n            });\n        });\n    \n  </script>\n</head>\n<body class=\"container\">\n    <section class=\"row\">\n        \n        <div class=\"col-md-6\"></div>\n        <div class=\"col-md-6\" id=\"jsgrid\">\n        </div>\n    </section>\n</body>\n</html>\n\n","x":1000,"y":200,"wires":[["117569d4e15e635d"]]},{"id":"037dce8e31058aab","type":"inject","z":"0338c3befa10e3ef","g":"dc42e32dff073243","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":105,"y":100,"wires":[["5fd8010a154e7b55"]],"l":false},{"id":"d433feb1.6365e","type":"http in","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","url":"/index","method":"get","upload":false,"swaggerDoc":"","x":120,"y":60,"wires":[["98b6cece.37871"]]},{"id":"98b6cece.37871","type":"template","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"web-template","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html lang=\"en\">\n   <head>\n      <!-- The jQuery library is a prerequisite for all jqSuite products -->\n      <script type=\"text/ecmascript\" src=\"http://www.guriddo.net/demo/js/jquery.min.js\"></script> \n      <!-- We support more than 40 localizations -->\n      <script type=\"text/ecmascript\" src=\"http://www.guriddo.net/demo/js/trirand/i18n/grid.locale-en.js\"></script>\n      <!-- This is the Javascript file of jqGrid -->   \n      <script type=\"text/ecmascript\" src=\"http://www.guriddo.net/demo/js/trirand/jquery.jqGrid.min.js\"></script>\n      <!-- This is the localization file of the grid controlling messages, labels, etc.\n      <!-- A link to a jQuery UI ThemeRoller theme, more than 22 built-in and many more custom -->\n      <link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"http://struts.jgeppert.com/struts2-jquery-grid-showcase/themes/showcase/jquery-ui.css\" />\n      <!-- The link to the CSS that the grid needs -->\n      <link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"http://www.guriddo.net/demo/css/trirand/ui.jqgrid.css\" />\n      <meta charset=\"utf-8\" />\n      <title>Demo CRUD with jqGrid</title>\n      <script type=\"text/javascript\"></script>\n      <link rel=\"stylesheet\" type=\"text/css\" href=\"http://www.guriddo.net/B1D671CF-E532-4481-99AA-19F420D90332/netdefender/hui/ndhui.css\" />\n   </head>\n   <body>\n      <script type=\"text/javascript\" language=\"javascript\" src=\"http://www.guriddo.net/B1D671CF-E532-4481-99AA-19F420D90332/netdefender/hui/ndhui.js?0=0&0=0&0=0\"></script>\n      <table id=\"jqGrid\"></table>\n      <div id=\"jqGridPager\"></div>\n      <script type=\"text/javascript\"> \n         $(document).ready(function () {\n             $(\"#jqGrid\").jqGrid({\n                 url: '/search',\n                 mtype: \"GET\",\n                 datatype: \"json\",\n                 colModel: [\n                     { label: 'ID', name: 'id', key: true, search: false, width: 75 },\n                     { label: 'Name', name: 'name', width: 150, editable: true, formoptions: { colpos: 1, rowpos: 1 }  },\n                     { label: 'Last Name', name: 'lastname', width: 150, editable: true, edittype: \"select\", formoptions: { colpos: 1, rowpos: 2 },\n                       editoptions: {\n                            dataUrl:'/search/lastname',\n                            type:\"GET\",\n                            buildSelect: function(data) {\n                                var response = jQuery.parseJSON(data); //JSON data\n                                var s = '<select>';\n                                if (response && response.length) {\n                                    s += '<option hidden=\"true\">--- Select Lastname ---</option>';\n                                    for (var i = 0, l=response.length; i<l ; i++) {\n                                    var id = response[i].id;\n                                    var val = response[i].value; \n                                    // You can concatenate ID or any other string here\n                                    //For example: var ri = response[i].id + response[i].value; \n                                        s += '<option value=\"'+id+'\">'+val+'</option>';\n                                    }\n                                }\n                                return s + \"</select>\";\n                            } \n                         } \n                     },\n                     { label: 'Code', name: 'code', width: 150, editable: true, formoptions: { colpos: 2, rowpos: 1 } },  \n                     { label: 'Married', name: 'married', width: 150, align: \"center\", search: false, editable: true, edittype: \"checkbox\", formatter: \"checkbox\", editoptions: { value: \"1:0\" }, formoptions: { colpos: 2, rowpos: 2 } }\n                 ],\n                 width: 500,\n                 height: 260,\n                 rowNum: 10,\n                 loadonce: true,\n                 viewrecords: true,\n                 pager: \"#jqGridPager\"\n             });\n             \n             $('#jqGrid').navGrid('#jqGridPager',\n                 // The buttons to appear on the toolbar of the grid\n                 { edit: true, add: true, del: true, search: true, refresh: true, view: true, position: \"left\", cloneToTop: true },\n                 \n                 // Options for the Edit Dialog\n                 {\n                     url: '/update',\n                     editCaption: \"The Edit Dialog\",\n                     recreateForm: true,\n\t\t\t\t\t //checkOnUpdate : true,\n\t\t\t\t\t //checkOnSubmit : true,\n\t\t\t\t\t beforeSubmit : function( postdata, form , oper) {\n\t\t\t\t\t\t if(confirm('Are you sure you want to update this information?') ) {\n\t\t\t\t\t\t\t // Do something\n\t\t\t\t\t\t \t return [true,'/update'];\n\t\t\t\t\t\t } else {\n\t\t\t\t\t\t\treturn [false, 'Update failed!'];\n\t\t\t\t\t\t }\n\t\t\t\t\t },\n                     afterSubmit: function () {\n                         $(this).jqGrid(\"setGridParam\", {datatype: 'json'});\n                         return [true];\n                     },\n                     closeAfterEdit: true,\n                     errorTextFormat: function (data) {\n                         return 'Error: ' + data.responseText\n                     }\n                 },\n                 // Options for the Add Dialog\n                 {\n                     url: '/insert',\n                     addCaption: \"Add Dialog\",\n                     afterSubmit: function () {\n                         $(this).jqGrid(\"setGridParam\", {datatype: 'json'});\n                         return [true];\n                     },\n                     closeAfterAdd: true,\n                     recreateForm: true,\n                     errorTextFormat: function (data) {\n                         return 'Error: ' + data.responseText\n                     }\n                 },\n                 // Options for the Delete Dialog\n                 {   \n                     url: '/delete',\n                     errorTextFormat: function (data) {\n                         return 'Error: ' + data.responseText\n                     }\n             });\n             $(\"#jqGrid\").jqGrid('filterToolbar', { stringResult: true, searchOnEnter: true });\n         });\n      </script>\n   </body>\n</html>","x":380,"y":60,"wires":[["3c1830eb.33b9"]]},{"id":"3c1830eb.33b9","type":"http response","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","statusCode":"","headers":{},"x":1100,"y":60,"wires":[]},{"id":"ef285826.0e9738","type":"http in","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","url":"/search","method":"get","upload":false,"swaggerDoc":"","x":130,"y":120,"wires":[["e396f56a.dcda38"]]},{"id":"e396f56a.dcda38","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"search-query","func":"//msg.topic=\"SELECT CONCAT('M00','',test.id) AS id,test.name AS name,lastname.lastname AS lastname,test.code AS code,test.married AS married FROM test INNER JOIN lastname ON lastname.id = test.lastname ORDER BY test.id DESC\";\nmsg.topic=\"SELECT test.id AS id,test.name AS name,lastname.lastname AS lastname,test.code AS code,test.married AS married FROM test INNER JOIN lastname ON lastname.id = test.lastname ORDER BY test.id DESC\";\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":120,"wires":[["9fe2ed80.2522c"]]},{"id":"458b0528.a4d98c","type":"http response","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","statusCode":"","headers":{},"x":1100,"y":120,"wires":[]},{"id":"d84f16f7.3d9698","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"search-response","func":"return msg;","outputs":1,"noerr":0,"x":765,"y":120,"wires":[["2b952c3a.f63884"]]},{"id":"2b952c3a.f63884","type":"json","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","property":"payload","action":"","pretty":false,"x":950,"y":120,"wires":[["458b0528.a4d98c"]]},{"id":"c91568f0.c3f2f8","type":"http in","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","url":"/insert","method":"post","upload":false,"swaggerDoc":"","x":130,"y":240,"wires":[["81bb8cdf.93e5b"]]},{"id":"e4b82091.b8e9a","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"insert-response","func":"msg.payload=msg.result;\nreturn msg;","outputs":1,"noerr":0,"x":755,"y":240,"wires":[["c224cbcf.e3e718"]]},{"id":"81bb8cdf.93e5b","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"insert-query","func":"msg.topic=\"INSERT INTO test (name,lastname,code,married,timestamp) VALUES ('\" + msg.payload.name + \"','\" + msg.payload.lastname + \"','\" + msg.payload.code + \"','\" + msg.payload.married + \"',CURRENT_TIMESTAMP)\";\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":240,"wires":[["50307401.f1297c"]]},{"id":"c224cbcf.e3e718","type":"http response","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","x":1100,"y":240,"wires":[]},{"id":"9929a22b.66471","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"lastname-query","func":"msg.topic=\"SELECT id, lastname as value FROM lastname\";\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":180,"wires":[["6ce2248e.9c889c"]]},{"id":"4bfc0ef6.e8511","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"lastname-response","func":"return msg;","outputs":1,"noerr":0,"x":765,"y":180,"wires":[["7b9f8d8b.c6d4e4"]]},{"id":"c70c0833.831ab8","type":"http in","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","url":"/search/lastname","method":"get","upload":false,"swaggerDoc":"","x":160,"y":180,"wires":[["9929a22b.66471"]]},{"id":"f92b07.fa8e84f8","type":"http response","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","statusCode":"","headers":{},"x":1100,"y":180,"wires":[]},{"id":"7b9f8d8b.c6d4e4","type":"json","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","property":"payload","action":"","pretty":false,"x":950,"y":180,"wires":[["f92b07.fa8e84f8"]]},{"id":"857ff60c.da9078","type":"http in","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","url":"/delete","method":"post","upload":false,"swaggerDoc":"","x":130,"y":360,"wires":[["5b19502.0bae0b"]]},{"id":"9a8b3fa.c0817c","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"delete-response","func":"msg.payload=msg.result;\nreturn msg;","outputs":1,"noerr":0,"x":755,"y":360,"wires":[["4520409.a2751c"]]},{"id":"5b19502.0bae0b","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"delete-query","func":"msg.topic=\"DELETE FROM test WHERE id='\" + msg.payload.id + \"'\";\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":360,"wires":[["973e8aa6.834338"]]},{"id":"4520409.a2751c","type":"http response","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","x":1100,"y":360,"wires":[]},{"id":"b9aef47c.8f0938","type":"http in","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","url":"/update","method":"post","upload":false,"swaggerDoc":"","x":130,"y":300,"wires":[["930f03c1.94bd5"]]},{"id":"ece93a93.ebc878","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"update-response","func":"msg.payload=msg.result;\nreturn msg;","outputs":1,"noerr":0,"x":765,"y":300,"wires":[["e51fe384.1db73"]]},{"id":"930f03c1.94bd5","type":"function","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"update-query","func":"msg.topic=\"UPDATE test SET name='\" + msg.payload.name + \"', lastname='\" + msg.payload.lastname + \"', code='\" + msg.payload.code + \"', married='\" + msg.payload.married + \"' WHERE id='\" + msg.payload.id + \"'\";\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":300,"wires":[["c1934c38.6647d"]]},{"id":"e51fe384.1db73","type":"http response","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","name":"","x":1100,"y":300,"wires":[]},{"id":"9fe2ed80.2522c","type":"mysql","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","mydb":"d48d08d1.d221d8","name":"database","x":570,"y":120,"wires":[["d84f16f7.3d9698"]]},{"id":"6ce2248e.9c889c","type":"mysql","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","mydb":"d48d08d1.d221d8","name":"database","x":570,"y":180,"wires":[["4bfc0ef6.e8511"]]},{"id":"50307401.f1297c","type":"mysql","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","mydb":"d48d08d1.d221d8","name":"database","x":570,"y":240,"wires":[["e4b82091.b8e9a"]]},{"id":"c1934c38.6647d","type":"mysql","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","mydb":"d48d08d1.d221d8","name":"database","x":570,"y":300,"wires":[["ece93a93.ebc878"]]},{"id":"973e8aa6.834338","type":"mysql","z":"c93ad5d5e0bf09e5","g":"7b144e46f5b6ec43","mydb":"d48d08d1.d221d8","name":"database","x":570,"y":360,"wires":[["9a8b3fa.c0817c"]]},{"id":"33f215417669f302","type":"http in","z":"bad1ea5a333cb4d4","d":true,"g":"b63843cb893f8f99","name":"","url":"/update","method":"put","upload":false,"swaggerDoc":"","x":130,"y":220,"wires":[["55b62a42ae2ad47c"]]},{"id":"2bb822373b452b47","type":"http response","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"","x":862,"y":220,"wires":[]},{"id":"ad333172fb04b7e2","type":"template","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"Web Template","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html lang=\"en-GB\">\n<head>\n    <title>Users</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/bootstrap-timepicker/0.5.2/css/bootstrap-timepicker.min.css\" />\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js\"></script>\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.css\" />\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid-theme.min.css\" />\n    <script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.js\"></script>\n\n    <script type=\"text/javascript\">\n        $(function () {\n            console.log(\"crud demo\");\n\n            var db = {{#payload}}{{{.}}}{{/payload}};\n\n            $(\"#jsgrid\").jsGrid({\n                width: \"100%\",\n                confirmDeleting: false,\n                inserting: true,\n                editing: true,\n                sorting: true,\n                paging: true,\n\n                data: db,\n\n                fields: [\n                    { title:\"ID\", name: \"id\", type: \"number\", width: 20, readOnly: true },\n                    { title:\"User ID\", name: \"userID\", type: \"text\", width: 50 },\n                    { title:\"First Name\", name: \"foreName\", type: \"text\", width: 50 },\n                    { title:\"Last Name\", name: \"sirName\", type: \"text\", width: 50 },\n                    { title:\"Age\", name: \"age\", type:\"number\", width: 25},\n                    { type: \"control\" }\n                ],\n           \n                controller: {\n                    insertItem: function(item) {\n                        return $.ajax({\n                            type: \"POST\",\n                            url: \"/insert\",\n                            data: item\n                        });\n                    },\n                    updateItem: function(item) {\n                       return $.ajax({\n                            type: \"PUT\",\n                            url: \"/update\",\n                            data: item\n                        });\n                    },\n                    deleteItem: function(item) {\n                        return $.ajax({\n                            type: \"DELETE\",\n                            url: \"/delete\",\n                            data: item\n                        });\n                    }\n                }   \n            });\n        });\n    \n  </script>\n</head>\n<body class=\"container\">\n    <section class=\"row\">\n        \n        <div class=\"col-md-6\"></div>\n        <div class=\"col-md-6\" id=\"jsgrid\">\n        </div>\n    </section>\n</body>\n</html>\n\n","x":652,"y":156,"wires":[["9f33e072997368b6"]]},{"id":"4a491b95e245e7c2","type":"http in","z":"bad1ea5a333cb4d4","d":true,"g":"b63843cb893f8f99","name":"","url":"/index","method":"get","upload":false,"swaggerDoc":"","x":120,"y":156,"wires":[["70a0e93542650b1f"]]},{"id":"9f33e072997368b6","type":"http response","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"","x":862,"y":156,"wires":[]},{"id":"577d77dde821fe0e","type":"http response","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"","x":862,"y":284,"wires":[]},{"id":"2a45b1abb1a49ad6","type":"http in","z":"bad1ea5a333cb4d4","d":true,"g":"b63843cb893f8f99","name":"","url":"/insert","method":"post","upload":false,"swaggerDoc":"","x":130,"y":284,"wires":[["849df9bee5b7e1c5"]]},{"id":"305b5d0d4c97d4dd","type":"http in","z":"bad1ea5a333cb4d4","d":true,"g":"b63843cb893f8f99","name":"","url":"/delete","method":"delete","upload":false,"swaggerDoc":"","x":140,"y":348,"wires":[["16d491dfbd02964e"]]},{"id":"098469ab1a800fe3","type":"http response","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"","x":862,"y":348,"wires":[]},{"id":"04955bf65de9fe2f","type":"function","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"Generate dummy data","func":"const firstNames =  [\"Liam\",\"Noah\",\"Oliver\",\"William\",\"Elijah\",\"James\",\"Benjamin\",\"Lucas\",\"Mason\",\"Ethan\",\"Alexander\",\"Henry\",\"Jacob\",\"Michael\",\"Daniel\",\"Logan\",\"Jackson\",\"Sebastian\",\"Jack\",\"Aiden\"];\nconst sirNames = [\"Jones\",\"Taylor\",\"Williams\",\"Brown\",\"White\",\"Harris\",\"Martin\",\"Davies\",\"Wilson\",\"Cooper\",\"Evans\",\"King\",\"Thomas\",\"Baker\",\"Green\",\"Wright\",\"Johnson\",\"Edwards\",\"Clark\",\"Roberts\",\"Robinson\",\"Hall\",\"Lewis\",\"Young\",\"Davis\",\"Turner\",\"Hill\",\"Phillips\",\"Collins\",\"Allen\",\"Moore\",\"Thompson\",\"Carter\",\"James\",\"Knight\",\"Walker\",\"Wood\",\"Hughes\",\"Parker\",\"Ward\",\"Bennett\",\"Cook\",\"Webb\",\"Bailey\",\"Scott\",\"Jackson\",\"Lee\",\"Cox\"];\n         \n         \n\nvar database = [];\n\nfor(let i = 1; i <= 30; i++) {\n    var item = {\"id\":i, \"timestamp\":Date.now()};\n    item.foreName = randomFirstname();\n    item.sirName = randomSirname();\n    item.userID = \"U\" + randomInt(1000, 2999);\n    item.age = randomInt(20, 65);\n    database.push(item);\n}\n\n\nfunction randomFirstname() {\n   return firstNames[randomInt(0, firstNames.length-1)];\n}\n\nfunction randomSirname() {\n    return sirNames[randomInt(0, sirNames.length-1)];\n}\n\nfunction randomInt(min, max) { \n  return Math.floor(Math.random() * (max - min + 1) + min);\n}\n\nflow.set(\"database\", database);\nmsg.payload = database;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":80,"wires":[["8cea908331c72a07"]]},{"id":"6445eb497e758dcc","type":"inject","z":"bad1ea5a333cb4d4","d":true,"g":"b63843cb893f8f99","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":95,"y":80,"wires":[["04955bf65de9fe2f"]],"l":false},{"id":"55b62a42ae2ad47c","type":"function","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"update-query","func":"\nvar database = flow.get(\"database\") || [];\n\nvar item = database.find(e => e.id == msg.payload.id );\n\nif(msg.payload.foreName == \"\" || msg.payload.sirName == \"\" || msg.payload.userID == \"\") {\n    msg.statusCode = 400;\n    msg.payload = null;\n    return msg;\n}\n\nif(item) {\n    item.foreName = msg.payload.foreName;\n    item.sirName = msg.payload.sirName;\n    item.age = msg.payload.age;\n    item.userID = msg.payload.userID;\n    flow.set(\"database\", database);\n} else {\n    msg.statusCode = 404;//not found\n    msg.payload = null;\n    return msg;\n}\nmsg.payload = item;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":322,"y":220,"wires":[["2bb822373b452b47"]]},{"id":"849df9bee5b7e1c5","type":"function","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"insert-query","func":"var database = flow.get(\"database\") || [];\nvar nextID = Math.max.apply(Math, database.map(function(o) { return o.id; })) + 1;\nvar item = {\n    id: nextID,\n    timestamp: Date.now(),\n    foreName : msg.payload.foreName,\n    sirName : msg.payload.sirName,\n    age : msg.payload.age,\n    userID : msg.payload.userID,\n}\n\nif(item.foreName == \"\" || item.sirName == \"\" || item.userID == \"\") {\n    msg.statusCode = 400;\n    msg.payload = null;\n    return msg;\n}\n\ndatabase.push(item);\nflow.set(\"database\", database);\n\nmsg.payload = item;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":322,"y":284,"wires":[["577d77dde821fe0e"]]},{"id":"16d491dfbd02964e","type":"function","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"delete-query","func":"\nvar database = flow.get(\"database\") || [];\n\ndatabase = database.filter(function( obj ) {\n    return obj.id != msg.payload.id;\n});\n\nflow.set(\"database\", database);\n\nmsg.payload = database;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":322,"y":348,"wires":[["098469ab1a800fe3"]]},{"id":"70a0e93542650b1f","type":"function","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"get database","func":"\nvar database = flow.get(\"database\") || [];\nmsg.payload = database;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":322,"y":156,"wires":[["7aea695d8fc1488c"]]},{"id":"7aea695d8fc1488c","type":"json","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","name":"","x":478,"y":156,"wires":[["ad333172fb04b7e2"]]},{"id":"8cea908331c72a07","type":"mongodb2 in","z":"bad1ea5a333cb4d4","g":"b63843cb893f8f99","service":"_ext_","configNode":"f6c122ad.621c98","name":"","collection":"LicencePlate","operation":"insert","x":640,"y":80,"wires":[[]]}]

Demo

demo

Credit

This flow is an adaption of the great flow developed by Steve-Mcl