Save tweets to a database and display on a webpage
This is a variation of the example flow demonstrated in the Node-RED Introduction video - https://www.youtube.com/watch?v=vYreeoCoQPI
Configuring the flow
After importing the flow, you will need to:
- authorise the Twitter node to access your account
- pick a hashtag it should search for (defaults to
#starwars
) - point the mongo nodes at an instance of mongodb (assumes it is running locally)
How it works
The main flow looks for tweets that match a given hashtag. They are then passed through sentiment analysis and tagged with an additional property based on whether they are deemed to be positive or negative. The tweets are then stored in a mongodb collection.
The second flow creates a HTTP endpoint at /tweets
. This returns a formatted page of the 5 most recent tweets stored in the database. They are colour coded based on their sentiment score.
There is a third flow provided that clears out the mongodb collection when injected.
[{"id":"87b919a8.7237c8","type":"inject","z":"49f7aed8.60937","name":"Clear Tweets","topic":"","payload":"{}","payloadType":"str","repeat":"","crontab":"","once":false,"x":190,"y":420,"wires":[["ab1c97b9.3443b8"]]},{"id":"53089f3b.e4a25","type":"mongodb out","z":"49f7aed8.60937","mongodb":"8ff7c7cd.26e048","name":"","collection":"tweets","payonly":false,"upsert":false,"multi":false,"operation":"delete","x":553,"y":415,"wires":[]},{"id":"ab1c97b9.3443b8","type":"json","z":"49f7aed8.60937","name":"","x":325,"y":420,"wires":[["53089f3b.e4a25"]]},{"id":"66ad421c.8763ec","type":"http response","z":"49f7aed8.60937","name":"","x":697,"y":345,"wires":[]},{"id":"d0355233.f7c02","type":"twitter in","z":"49f7aed8.60937","twitter":"","tags":"#starwars","user":"false","name":"","topic":"tweets","x":155,"y":89,"wires":[["7525f2c2.dc288c"]]},{"id":"4c90a634.72c4c8","type":"debug","z":"49f7aed8.60937","name":"","active":true,"console":"false","complete":"false","x":623,"y":93,"wires":[]},{"id":"bf59d485.a49d28","type":"mongodb out","z":"49f7aed8.60937","mongodb":"8ff7c7cd.26e048","name":"Save Tweets","collection":"tweets","payonly":false,"upsert":false,"multi":false,"operation":"store","x":621,"y":133,"wires":[]},{"id":"c068fa5f.5beb48","type":"http in","z":"49f7aed8.60937","name":"","url":"/tweets","method":"get","swaggerDoc":"","x":159,"y":154,"wires":[["34dfcae6.aa4756"]]},{"id":"38644a8b.eb24a6","type":"mongodb in","z":"49f7aed8.60937","mongodb":"8ff7c7cd.26e048","name":"Retrieve Tweets","collection":"tweets","operation":"find","x":394,"y":277,"wires":[["e2828cd0.51057"]]},{"id":"e2828cd0.51057","type":"template","z":"49f7aed8.60937","name":"Styled Tweets","field":"payload","format":"handlebars","template":"<html>\n<head>\n <style>\nbody {\n text-align:center;\n}\nul {\n text-align:left;\n width: 500px;\n margin: auto;\n list-style-type:none;\n}\nli {\n border: 1px solid #999;\n border-left-width: 10px;\n border-radius: 3px;\n margin-bottom: 20px;\n padding: 10px;\n}\nli.sentiment_positive {\n border-left: 10px solid #69B369;\n}\nli.sentiment_negative {\n border-left: 10px solid #E64444;\n}\n.tweet {\n display: inline-block;\n font-family: Helvetica;\n width: 380px;\n margin-left: 10px;\n}\nimg {\n width: 48px;\n height: 48px;\n border-radius: 5px;\n vertical-align: top;\n}\n</style>\n\n</head>\n<body>\n\n<ul>\n{{#payload}}\n<li class=\"sentiment_{{sentiment.text}}\">\n <img src=\"{{tweet.user.profile_image_url}}\"/>\n <div class=\"tweet\">\n <div class=\"user\"><b>{{tweet.user.name}}</b> <small>@{{tweet.user.screen_name}}</small></div>\n <div class=\"text\">{{tweet.text}}</div>\n </div></li>\n{{/payload}}\n</ul>\n</body>\n</html>","x":581,"y":297,"wires":[["66ad421c.8763ec"]]},{"id":"34dfcae6.aa4756","type":"function","z":"49f7aed8.60937","name":"Limit/Sort","func":"msg.sort = {\"tweet.id\":-1};\nmsg.limit = 5;\nmsg.skip = 0;\nreturn msg;","outputs":1,"noerr":0,"x":296,"y":208,"wires":[["38644a8b.eb24a6"]]},{"id":"7525f2c2.dc288c","type":"sentiment","z":"49f7aed8.60937","name":"","x":294,"y":89,"wires":[["85b30950.448128"]]},{"id":"85b30950.448128","type":"function","z":"49f7aed8.60937","name":"","func":"if(msg.sentiment.score > 0 ) {\n msg.sentiment.text = \"positive\";\n} else if (msg.sentiment.score < 0) {\n msg.sentiment.text = \"negative\";\n}\nreturn msg;","outputs":1,"noerr":0,"x":431,"y":89,"wires":[["4c90a634.72c4c8","bf59d485.a49d28"]]},{"id":"7be2a2ea.401dbc","type":"template","z":"49f7aed8.60937","name":"Simple Tweet","field":"payload","format":"handlebars","template":"<ul>\n{{#payload}}\n <li>{{tweet.text}}</li>\n{{/payload}}\n</ul>","x":587,"y":233,"wires":[[]]},{"id":"8ff7c7cd.26e048","type":"mongodb","z":"49f7aed8.60937","hostname":"127.0.0.1","port":"27017","db":"tweets","name":""}]