diff options
author | 2017-08-28 05:25:46 -0900 | |
---|---|---|
committer | 2017-08-28 05:36:52 -0900 | |
commit | d1569975bb18f4359fac18aa98f55b69c248a3ad (patch) | |
tree | c8681eeac12dca8673ccf841705daac88bf01ca6 /dgbuilder/core_nodes/storage | |
parent | a016ea661ff5767a3539734c4c07ef974a6e4614 (diff) |
[CCSDK-28] populated the seed code for dgbuilder
updated the code to point to the new package name for sli
Change-Id: I3b5a1d05dc5193664fd4a667afdcd0b2354010a4
Issue-ID:{CCSDK-28}
Signed-off-by: Chinthakayala, Sheshashailavas (sc2914) <sc2914@att.com>
Signed-off-by: Chinthakayala, Sheshashailavas (sc2914) <sc2914@att.com>
Diffstat (limited to 'dgbuilder/core_nodes/storage')
-rw-r--r-- | dgbuilder/core_nodes/storage/28-tail.html | 58 | ||||
-rw-r--r-- | dgbuilder/core_nodes/storage/28-tail.js | 69 | ||||
-rw-r--r-- | dgbuilder/core_nodes/storage/50-file.html | 110 | ||||
-rw-r--r-- | dgbuilder/core_nodes/storage/50-file.js | 93 | ||||
-rw-r--r-- | dgbuilder/core_nodes/storage/65-redisout.html | 105 | ||||
-rw-r--r-- | dgbuilder/core_nodes/storage/65-redisout.js | 107 | ||||
-rw-r--r-- | dgbuilder/core_nodes/storage/66-mongodb.html | 231 | ||||
-rw-r--r-- | dgbuilder/core_nodes/storage/66-mongodb.js | 233 |
8 files changed, 1006 insertions, 0 deletions
diff --git a/dgbuilder/core_nodes/storage/28-tail.html b/dgbuilder/core_nodes/storage/28-tail.html new file mode 100644 index 00000000..c094d064 --- /dev/null +++ b/dgbuilder/core_nodes/storage/28-tail.html @@ -0,0 +1,58 @@ +<!-- + Copyright 2013 IBM Corp. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<script type="text/x-red" data-template-name="tail"> + <div class="form-row node-input-filename"> + <label for="node-input-filename"><i class="fa fa-file"></i> Filename</label> + <input type="text" id="node-input-filename" placeholder="Filename"> + </div> + <div class="form-row"> + <label> </label> + <input type="checkbox" id="node-input-split" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;"> + <label for="node-input-split" style="width: 70%;">Split lines if we see \n ?</label> + </div> + <div class="form-row"> + <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> + <input type="text" id="node-input-name" placeholder="Name"> + </div> + <!-- <div class="form-tips">WON'T work on Windows.</div> --> +</script> + +<script type="text/x-red" data-help-name="tail"> + <p>Tails (watches for things to be added) to the configured file. (Linux/Mac ONLY)</p> + <p>This won't work on Windows filesystems, as it relies on the tail -F command.</p> +</script> + +<script type="text/javascript"> + RED.nodes.registerType('tail',{ + category: 'storage-input', + defaults: { + name: {value:""}, + split: {value:false}, + filename: {value:"",required:true} + }, + color:"BurlyWood", + inputs:0, + outputs:1, + icon: "file.png", + label: function() { + return this.name||this.filename; + }, + labelStyle: function() { + return this.name?"node_label_italic":""; + } + }); +</script> diff --git a/dgbuilder/core_nodes/storage/28-tail.js b/dgbuilder/core_nodes/storage/28-tail.js new file mode 100644 index 00000000..89c7a639 --- /dev/null +++ b/dgbuilder/core_nodes/storage/28-tail.js @@ -0,0 +1,69 @@ +/** + * Copyright 2013, 2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +module.exports = function(RED) { + "use strict"; + var spawn = require('child_process').spawn; + var plat = require('os').platform(); + + if (plat.match(/^win/)) { + throw "Info : Currently not supported on Windows."; + } + + function TailNode(n) { + RED.nodes.createNode(this,n); + + this.filename = n.filename; + this.split = n.split; + var node = this; + + var err = ""; + // TODO: rewrite to use node-tail + var tail = spawn("tail", ["-F", "-n", "0", this.filename]); + tail.stdout.on("data", function (data) { + if (node.split) { + // TODO: allow customisation of the line break - as we do elsewhere + var strings = data.toString().split("\n"); + for (var s in strings) { + //TODO: should we really filter blanks? Is that expected? + if (strings[s] !== "") { + node.send({ + topic: node.filename, + payload: strings[s] + }); + } + } + } + else { + var msg = { + topic:node.filename, + payload: data.toString() + }; + node.send(msg); + } + }); + + tail.stderr.on("data", function(data) { + node.warn(data.toString()); + }); + + this.on("close", function() { + if (tail) { tail.kill(); } + }); + } + + RED.nodes.registerType("tail",TailNode); +} diff --git a/dgbuilder/core_nodes/storage/50-file.html b/dgbuilder/core_nodes/storage/50-file.html new file mode 100644 index 00000000..5113a17d --- /dev/null +++ b/dgbuilder/core_nodes/storage/50-file.html @@ -0,0 +1,110 @@ +<!-- + Copyright 2013, 2014 IBM Corp. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<script type="text/x-red" data-template-name="file"> + <div class="form-row node-input-filename"> + <label for="node-input-filename"><i class="fa fa-file"></i> Filename</label> + <input type="text" id="node-input-filename" placeholder="Filename"> + </div> + <div class="form-row"> + <label> </label> + <input type="checkbox" id="node-input-appendNewline" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;"> + <label for="node-input-appendNewline" style="width: 70%;">Append newline ?</label> + </div> + <div class="form-row"> + <label> </label> + <input type="checkbox" id="node-input-overwriteFile" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;"> + <label for="node-input-overwriteFile" style="width: 70%;">Overwrite complete file ?</label> + </div> + <div class="form-row"> + <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> + <input type="text" id="node-input-name" placeholder="Name"> + </div> +</script> + +<script type="text/x-red" data-help-name="file"> + <p>Writes <b>msg.payload</b> to the file specified, e.g. to create a log.</p> + <p>The filename can be overridden by the <b>msg.filename</b> property of the incoming message.</p> + <p>A newline is added to every message. But this can be turned off if required, for example, to allow binary files to be written.</p> + <p>The default behaviour is to append to the file. This can be changed to overwrite the file each time, for example if you want to output a "static" web page or report.</p> + <p>If a <b>msg.delete</b> property exists then the file will be deleted instead.</p> +</script> + +<script type="text/x-red" data-template-name="file in"> + <div class="form-row"> + <label for="node-input-filename"><i class="fa fa-file"></i> Filename</label> + <input type="text" id="node-input-filename" placeholder="Filename"> + </div> + <div class="form-row"> + <label for="node-input-format"><i class="fa fa-sign-out"></i> Output as</label> + <select id="node-input-format"> + <option value="utf8">a utf8 string</option> + <option value="">a Buffer</option> + </select> + </div> + <div class="form-row"> + <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> + <input type="text" id="node-input-name" placeholder="Name"> + </div> +</script> + +<script type="text/x-red" data-help-name="file in"> + <p>Reads the specified file and sends the content as <b>msg.payload</b>, and the filename as <b>msg.filename</b>.</p> + <p>The filename can be overridden by the <b>msg.filename</b> property of the incoming message.</p> +</script> + +<script type="text/javascript"> + RED.nodes.registerType('file',{ + category: 'storage-output', + defaults: { + name: {value:""}, + filename: {value:""}, + appendNewline: {value:true}, + overwriteFile: {value:false} + }, + color:"BurlyWood", + inputs:1, + outputs:0, + icon: "file.png", + align: "right", + label: function() { + return this.name||this.filename; + }, + labelStyle: function() { + return this.name?"node_label_italic":""; + } + }); + + RED.nodes.registerType('file in',{ + category: 'storage-input', + defaults: { + name: {value:""}, + filename: {value:""}, + format: {value:"utf8"}, + }, + color:"BurlyWood", + inputs:1, + outputs:1, + icon: "file.png", + label: function() { + return this.name||this.filename; + }, + labelStyle: function() { + return this.name?"node_label_italic":""; + } + }); + +</script> diff --git a/dgbuilder/core_nodes/storage/50-file.js b/dgbuilder/core_nodes/storage/50-file.js new file mode 100644 index 00000000..d6cc4410 --- /dev/null +++ b/dgbuilder/core_nodes/storage/50-file.js @@ -0,0 +1,93 @@ +/** + * Copyright 2013, 2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +module.exports = function(RED) { + "use strict"; + var fs = require("fs"); + + function FileNode(n) { + RED.nodes.createNode(this,n); + this.filename = n.filename || ""; + this.appendNewline = n.appendNewline; + this.overwriteFile = n.overwriteFile; + var node = this; + this.on("input",function(msg) { + var filename = msg.filename || this.filename; + if (filename === "") { + node.warn('No filename specified'); + } else if (msg.hasOwnProperty('delete')) { + fs.unlink(filename, function (err) { + if (err) { node.warn('Failed to delete file : '+err); } + //console.log('Deleted file",filename); + }); + } else if (typeof msg.payload != "undefined") { + var data = msg.payload; + if (typeof data === "object") { + if (!Buffer.isBuffer(data)) { + data = JSON.stringify(data); + } + } + if (typeof data === "boolean") { data = data.toString(); } + if ((this.appendNewline)&&(!Buffer.isBuffer(data))) { data += "\n"; } + if (this.overwriteFile) { + // using "binary" not {encoding:"binary"} to be 0.8 compatible for a while + fs.writeFile(filename, data, "binary", function (err) { + if (err) { node.warn('Failed to write to file : '+err); } + //console.log('Message written to file',filename); + }); + } + else { + // using "binary" not {encoding:"binary"} to be 0.8 compatible for a while + fs.appendFile(filename, data, "binary", function (err) { + if (err) { node.warn('Failed to append to file : '+err); } + //console.log('Message appended to file',filename); + }); + } + } + }); + } + RED.nodes.registerType("file",FileNode); + + function FileInNode(n) { + RED.nodes.createNode(this,n); + + this.filename = n.filename || ""; + this.format = n.format; + var node = this; + var options = {}; + if (this.format) { + options['encoding'] = this.format; + } + this.on("input",function(msg) { + var filename = msg.filename || this.filename; + if (filename === "") { + node.warn('No filename specified'); + } else { + fs.readFile(filename,options,function(err,data) { + if (err) { + node.warn(err); + msg.error = err; + } else { + msg.filename = filename; + msg.payload = data; + } + node.send(msg); + }); + } + }); + } + RED.nodes.registerType("file in",FileInNode); +} diff --git a/dgbuilder/core_nodes/storage/65-redisout.html b/dgbuilder/core_nodes/storage/65-redisout.html new file mode 100644 index 00000000..9000dfd6 --- /dev/null +++ b/dgbuilder/core_nodes/storage/65-redisout.html @@ -0,0 +1,105 @@ +<!-- + Copyright 2013 IBM Corp. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<script type="text/x-red" data-template-name="redis out"> + <div class="form-row node-input-hostname"> + <label for="node-input-hostname"><i class="fa fa-bookmark"></i> Host</label> + <input class="input-append-left" type="text" id="node-input-hostname" placeholder="127.0.0.1" style="width: 40%;" ><button id="node-input-hostname-lookup" class="btn input-append-right"><span class="caret"></span></button> + <label for="node-input-port" style="margin-left: 10px; width: 35px; "> Port</label> + <input type="text" id="node-input-port" placeholder="6379" style="width:45px"> + </div> + <div class="form-row"> + <label for="node-input-key"><i class="fa fa-key"></i> Key</label> + <input type="text" id="node-input-key" placeholder="Redis Key"> + </div> + <div class="form-row"> + <label for="node-input-type"><i class="fa fa-th"></i> Type</label> + <select type="text" id="node-input-structtype" style="width: 150px;"> + <option value="string">String</option> + <option value="hash">Hash</option> + <option value="set">Set</option> + <option value="list">List</option> + </select> + </div> + <div class="form-row"> + <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> + <input type="text" id="node-input-name" placeholder="Name"> + </div> + <div class="form-tips"> + If key is blank, the topic will be used as the key.<br> + If type is hash, payload should be field=value. + </div> +</script> + +<script type="text/x-red" data-help-name="redis out"> + <p>A Redis output node. Options include Hash, Set, List and String.</p> + <p>To run this you need a local Redis server running. For details see <a href="http://redis.io/" target="_new">the Redis site</a>.</p> +</script> + +<script type="text/javascript"> + RED.nodes.registerType('redis out',{ + category: 'storage-output', + color:"#ffaaaa", + defaults: { + hostname: { value:"127.0.0.1",required:true}, + port: { value: 6379,required:true}, + name: {value:""}, + key: {value:""}, + structtype: {value:"",required:true} + }, + inputs:1, + outputs:0, + icon: "redis.png", + align: "right", + label: function() { + return this.name||this.key+" ("+this.structtype+")"; + }, + oneditprepare: function() { + var availableServers = []; + var matchedServers = {}; + RED.nodes.eachNode(function(node) { + if (node.type == "redis out" && node.hostname && node.port && !matchedServers[node.hostname+":"+node.port]) { + var label = node.hostname+":"+node.port; + matchedServers[label] = true; + availableServers.push({ + label:label, + value:node.hostname, + port:node.port + }); + } + }); + $( "#node-input-hostname" ).autocomplete({ + minLength: 0, + source: availableServers, + select: function( event, ui ) { + $("#node-input-port").val(ui.item.port); + } + }); + var tt = this; + tt._acOpen = false; + $( "#node-input-hostname" ).on( "autocompleteclose", function( event, ui ) { tt._acOpen = false;} ); + $( "#node-input-hostname-lookup" ).click(function(e) { + if (tt._acOpen) { + $( "#node-input-hostname" ).autocomplete( "close"); + } else { + $( "#node-input-hostname" ).autocomplete( "search", "" ); + } + tt._acOpen = !tt._acOpen; + e.preventDefault(); + }); + } + }); +</script> diff --git a/dgbuilder/core_nodes/storage/65-redisout.js b/dgbuilder/core_nodes/storage/65-redisout.js new file mode 100644 index 00000000..907e2a55 --- /dev/null +++ b/dgbuilder/core_nodes/storage/65-redisout.js @@ -0,0 +1,107 @@ +/** + * Copyright 2013 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +module.exports = function(RED) { + "use strict"; + var util = require("util"); + var redis = require("redis"); + + var hashFieldRE = /^([^=]+)=(.*)$/; + + var redisConnectionPool = function() { + var connections = {}; + var obj = { + get: function(host,port) { + var id = host+":"+port; + if (!connections[id]) { + connections[id] = redis.createClient(port,host); + connections[id].on("error",function(err) { + util.log("[redis] "+err); + }); + connections[id].on("connect",function() { + util.log("[redis] connected to "+host+":"+port); + }); + connections[id]._id = id; + connections[id]._nodeCount = 0; + } + connections[id]._nodeCount += 1; + return connections[id]; + }, + close: function(connection) { + connection._nodeCount -= 1; + if (connection._nodeCount === 0) { + if (connection) { + clearTimeout(connection.retry_timer); + connection.end(); + } + delete connections[connection._id]; + } + } + }; + return obj; + }(); + + + function RedisOutNode(n) { + RED.nodes.createNode(this,n); + this.port = n.port||"6379"; + this.hostname = n.hostname||"127.0.0.1"; + this.key = n.key; + this.structtype = n.structtype; + + this.client = redisConnectionPool.get(this.hostname,this.port); + + if (this.client.connected) { + this.status({fill:"green",shape:"dot",text:"connected"}); + } else { + this.status({fill:"red",shape:"ring",text:"disconnected"},true); + } + + var node = this; + this.client.on("end", function() { + node.status({fill:"red",shape:"ring",text:"disconnected"}); + }); + this.client.on("connect", function() { + node.status({fill:"green",shape:"dot",text:"connected"}); + }); + + this.on("input", function(msg) { + var k = this.key || msg.topic; + if (k) { + if (this.structtype == "string") { + this.client.set(k,RED.util.ensureString(msg.payload)); + } else if (this.structtype == "hash") { + var r = hashFieldRE.exec(msg.payload); + if (r) { + this.client.hset(k,r[1],r[2]); + } else { + this.warn("Invalid payload for redis hash"); + } + } else if (this.structtype == "set") { + this.client.sadd(k,msg.payload); + } else if (this.structtype == "list") { + this.client.rpush(k,msg.payload); + } + } else { + this.warn("No key or topic set"); + } + }); + this.on("close", function() { + redisConnectionPool.close(node.client); + }); + } + RED.nodes.registerType("redis out",RedisOutNode); +} diff --git a/dgbuilder/core_nodes/storage/66-mongodb.html b/dgbuilder/core_nodes/storage/66-mongodb.html new file mode 100644 index 00000000..81c56389 --- /dev/null +++ b/dgbuilder/core_nodes/storage/66-mongodb.html @@ -0,0 +1,231 @@ +<!-- + Copyright 2013,2014 IBM Corp. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<script type="text/x-red" data-template-name="mongodb"> + <div class="form-row"> + <label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> Host</label> + <input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" > + <label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label> + <input type="text" id="node-config-input-port" placeholder="27017" style="width:45px"> + </div> + <div class="form-row"> + <label for="node-config-input-db"><i class="fa fa-database"></i> Database</label> + <input type="text" id="node-config-input-db" placeholder="test"> + </div> + <div class="form-row"> + <label for="node-config-input-user"><i class="fa fa-user"></i> Username</label> + <input type="text" id="node-config-input-user"> + </div> + <div class="form-row"> + <label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label> + <input type="password" id="node-config-input-password"> + </div> + <div class="form-row"> + <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label> + <input type="text" id="node-config-input-name" placeholder="Name"> + </div> +</script> + +<script type="text/javascript"> + RED.nodes.registerType('mongodb', { + category: 'config', + color: "rgb(218, 196, 180)", + defaults: { + hostname: {value: "127.0.0.1", required: true}, + port: {value: 27017, required: true}, + db: {value: "", required: true}, + name: {value: ""} + }, + credentials: { + user: {type: "text"}, + password: {type: "password"} + }, + label: function() { + return this.name || this.hostname + ":" + this.port + "/" + this.db; + } + }); +</script> + + +<script type="text/x-red" data-template-name="mongodb out"> + <div class="form-row"> + <label for="node-input-mongodb"><i class="fa fa-bookmark"></i> Server</label> + <input type="text" id="node-input-mongodb"> + </div> + <div class="form-row"> + <label for="node-input-collection"><i class="fa fa-briefcase"></i> Collection</label> + <input type="text" id="node-input-collection" placeholder="collection"> + </div> + <div class="form-row"> + <label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label> + <select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;"> + <option value="store">save</option> + <option value="insert">insert</option> + <option value="update">update</option> + <option value="delete">remove</option> + </select> + </div> + <div class="form-row node-input-payonly"> + <label> </label> + <input type="checkbox" id="node-input-payonly" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;"> + <label for="node-input-payonly" style="width: 70%;">Only store msg.payload object</label> + </div> + <div class="form-row node-input-upsert"> + <label> </label> + <input type="checkbox" id="node-input-upsert" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;"> + <label for="node-input-upsert" style="width: 70%;">Create a new document if no match found</label> + </div> + <div class="form-row node-input-multi"> + <label> </label> + <input type="checkbox" id="node-input-multi" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;;"> + <label for="node-input-multi" style="width: 70%;">Update all matching documents</label> + </div> + <div class="form-row"> + <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> + <input type="text" id="node-input-name" placeholder="Name"> + </div> + <div class="form-tips" id="node-warning" style="display: none"><b> Tip:</b> If no collection is set, ensure <b>msg.collection</b> will contain the collection name + </div> +</script> + +<script type="text/x-red" data-help-name="mongodb out"> + <p>A simple MongoDB output node. Can save, insert, update and remove objects from a chosen collection.</p> + <p>Save will update an existing object or insert a new object if one does not already exist.</p> + <p>Insert will insert a new object.</p> + <p>Save and insert either store <b>msg</b> or <b>msg.payload</b>.</p> + <p>Update will modify an existing object or objects. The query to select objects to update uses <b>msg.query</b> and the update to the element uses <b>msg.payload</b>.</p> + <p>Update can add a object if it does not exist or update multiple objects.</p> + <p>Remove will remove objects that match the query passed in on <b>msg.payload</b>. A blank query will delete <i>all of the objects</i> in the collection.</p> + <p>You can either set the collection method in the node config or on <b>msg.collection</b>. Setting it in the node will override <b>msg.collection</b>.</p> + <p>By default MongoDB creates an <i>_id</i> property as the primary key - so repeated injections of the same <b>msg</b> will result in many database entries.</p> + <p>If this is NOT the desired behaviour - ie. you want repeated entries to overwrite, then you must set the <b>msg._id</b> property to be a constant by the use of a previous function node.</p> + <p>This could be a unique constant or you could create one based on some other msg property.</p> + <p>Currently we do not limit or cap the collection size at all... this may well change.</p> +</script> + +<script type="text/javascript"> + + function oneditprepare() { + $("#node-input-operation").change(function () { + var id = $("#node-input-operation option:selected").val(); + + if (id === "update") { + $(".node-input-payonly").hide(); + $(".node-input-upsert, .node-input-multi").show(); + } else if (id === "delete") { + $(".node-input-payonly, .node-input-upsert, .node-input-multi").hide(); + } else { + $(".node-input-payonly").show(); + $(".node-input-upsert, .node-input-multi").hide(); + } + }); + + $("#node-input-collection").change(function () { + if($("#node-input-collection").val() === "") { + $("#node-warning").show(); + } else { + $("#node-warning").hide(); + } + }); + } + + RED.nodes.registerType('mongodb out', { + category: 'storage-output', + color: "rgb(218, 196, 180)", + defaults: { + mongodb: {type: "mongodb", required: true}, + name: {value: ""}, + collection: {value: ""}, + payonly: {value: false}, + upsert: {value: false}, + multi: {value: false}, + operation: {value: "store"} + }, + inputs: 1, + outputs: 0, + icon: "mongodb.png", + align: "right", + label: function() { + var mongoNode = RED.nodes.node(this.mongodb); + return this.name || (mongoNode ? mongoNode.label() + " " + this.collection: "mongodb"); + }, + labelStyle: function() { + return this.name ? "node_label_italic" : ""; + }, + oneditprepare: oneditprepare + }); +</script> + + +<script type="text/x-red" data-template-name="mongodb in"> + <div class="form-row"> + <label for="node-input-mongodb"><i class="fa fa-bookmark"></i> Server</label> + <input type="text" id="node-input-mongodb"> + </div> + <div class="form-row"> + <label for="node-input-collection"><i class="fa fa-briefcase"></i> Collection</label> + <input type="text" id="node-input-collection" placeholder="collection"> + </div> + <div class="form-row"> + <label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label> + <select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;"> + <option value="find">find</option> + <option value="count">count</option> + <option value="aggregate">aggregate</option> + </select> + </div> + <div class="form-row"> + <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> + <input type="text" id="node-input-name" placeholder="Name"> + </div> + <div class="form-tips" id="node-warning" style="display: none"><b> Tip:</b> If no collection is set, ensure <b>msg.collection</b> will contain the collection name + </div> +</script> + +<script type="text/x-red" data-help-name="mongodb in"> + <p>Calls a MongoDB collection method based on the selected operator.</p> + <p>Find queries a collection using the <b>msg.payload</b> as the query statement as per the .find() function. Optionally, you may also (via a function) set a <b>msg.projection</b> object to constrain the returned fields, a <b>msg.sort</b> object and a <b>msg.limit</b> object.</p> + <p>Count returns a count of the number of documents in a collection or matching a query using the <b>msg.payload</b> as the query statement.</p> + <p>Aggregate provides access to the aggregation pipeline using the <b>msg.payload</b> as the pipeline array.</p> + <p>You can override the collection the method is performed on by setting <b>msg.collection</b> to the desired collection name.</p> + <p>See the <a href="http://docs.mongodb.org/manual/reference/method/db.collection.find/" target="new"><i>MongoDB collection methods docs</i></a> for examples.</p> + <p>The result is returned in <b>msg.payload</b>.</p> +</script> + +<script type="text/javascript"> + + RED.nodes.registerType('mongodb in', { + category: 'storage-input', + color: "rgb(218, 196, 180)", + defaults: { + mongodb: {type: "mongodb", required: true}, + name: {value: ""}, + collection: {value: ""}, + operation: {value: "find"} + }, + inputs: 1, + outputs: 1, + icon: "mongodb.png", + label: function() { + var mongoNode = RED.nodes.node(this.mongodb); + return this.name || (mongoNode ? mongoNode.label() + " " + this.collection: "mongodb"); + }, + labelStyle: function() { + return this.name ? "node_label_italic" : ""; + }, + oneditprepare: oneditprepare + }); +</script> diff --git a/dgbuilder/core_nodes/storage/66-mongodb.js b/dgbuilder/core_nodes/storage/66-mongodb.js new file mode 100644 index 00000000..3a71407c --- /dev/null +++ b/dgbuilder/core_nodes/storage/66-mongodb.js @@ -0,0 +1,233 @@ +/** + * Copyright 2013,2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +module.exports = function(RED) { + "use strict"; + var mongo = require('mongodb'); + var MongoClient = mongo.MongoClient; + + function MongoNode(n) { + RED.nodes.createNode(this,n); + this.hostname = n.hostname; + this.port = n.port; + this.db = n.db; + this.name = n.name; + + var url = "mongodb://"; + if (this.credentials && this.credentials.user && this.credentials.password) { + url += this.credentials.user+":"+this.credentials.password+"@"; + } + url += this.hostname+":"+this.port+"/"+this.db; + + this.url = url; + } + + RED.nodes.registerType("mongodb",MongoNode,{ + credentials: { + user: {type:"text"}, + password: {type: "password"} + } + }); + + function ensureValidSelectorObject(selector) { + if (selector != null && (typeof selector != 'object' || Buffer.isBuffer(selector))) { + return {}; + } + return selector; + } + + + function MongoOutNode(n) { + RED.nodes.createNode(this,n); + this.collection = n.collection; + this.mongodb = n.mongodb; + this.payonly = n.payonly || false; + this.upsert = n.upsert || false; + this.multi = n.multi || false; + this.operation = n.operation; + this.mongoConfig = RED.nodes.getNode(this.mongodb); + + if (this.mongoConfig) { + var node = this; + MongoClient.connect(this.mongoConfig.url, function(err, db) { + if (err) { + node.error(err); + } else { + node.clientDb = db; + var coll; + if (node.collection) { + coll = db.collection(node.collection); + } + node.on("input",function(msg) { + if (!coll) { + if (msg.collection) { + coll = db.collection(msg.collection); + } else { + node.error("No collection defined"); + return; + } + } + delete msg._topic; + delete msg.collection; + if (node.operation === "store") { + if (node.payonly) { + if (typeof msg.payload !== "object") { + msg.payload = {"payload": msg.payload}; + } + coll.save(msg.payload,function(err, item) { + if (err) { + node.error(err); + } + }); + } else { + coll.save(msg,function(err, item) { + if (err) { + node.error(err); + } + }); + } + } else if (node.operation === "insert") { + if (node.payonly) { + if (typeof msg.payload !== "object") { + msg.payload = {"payload": msg.payload}; + } + coll.insert(msg.payload, function(err, item) { + if (err) { + node.error(err); + } + }); + } else { + coll.insert(msg, function(err,item) { + if (err) { + node.error(err); + } + }); + } + } else if (node.operation === "update") { + if (typeof msg.payload !== "object") { + msg.payload = {"payload": msg.payload}; + } + var query = msg.query || {}; + var payload = msg.payload || {}; + var options = { + upsert: node.upsert, + multi: node.multi + }; + + coll.update(query, payload, options, function(err, item) { + if (err) { + node.error(err + " " + payload); + } + }); + } else if (node.operation === "delete") { + coll.remove(msg.payload, function(err, items) { + if (err) { + node.error(err); + } + }); + } + }); + } + }); + } else { + this.error("missing mongodb configuration"); + } + + this.on("close", function() { + if (this.clientDb) { + this.clientDb.close(); + } + }); + } + RED.nodes.registerType("mongodb out",MongoOutNode); + + function MongoInNode(n) { + RED.nodes.createNode(this,n); + this.collection = n.collection; + this.mongodb = n.mongodb; + this.operation = n.operation || "find"; + this.mongoConfig = RED.nodes.getNode(this.mongodb); + + if (this.mongoConfig) { + var node = this; + MongoClient.connect(this.mongoConfig.url, function(err,db) { + if (err) { + node.error(err); + } else { + node.clientDb = db; + var coll; + if (node.collection) { + coll = db.collection(node.collection); + } + node.on("input", function(msg) { + if (!coll) { + if (msg.collection) { + coll = db.collection(msg.collection); + } else { + node.error("No collection defined"); + return; + } + } + if (node.operation === "find") { + msg.projection = msg.projection || {}; + var selector = ensureValidSelectorObject(msg.payload); + coll.find(selector,msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) { + if (err) { + node.error(err); + } else { + msg.payload = items; + delete msg.projection; + delete msg.sort; + delete msg.limit; + node.send(msg); + } + }); + } else if (node.operation === "count") { + var selector = ensureValidSelectorObject(msg.payload); + coll.count(selector, function(err, count) { + if (err) { + node.error(err); + } else { + msg.payload = count; + node.send(msg); + } + }); + } else if (node.operation === "aggregate") { + msg.payload = (msg.payload instanceof Array) ? msg.payload : []; + coll.aggregate(msg.payload, function(err, result) { + if (err) { + node.error(err); + } else { + msg.payload = result; + node.send(msg); + } + }); + } + }); + } + }); + } else { + this.error("missing mongodb configuration"); + } + + this.on("close", function() { + if (this.clientDb) { + this.clientDb.close(); + } + }); + } + RED.nodes.registerType("mongodb in",MongoInNode); +} |