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:

  1. authorise the Twitter node to access your account
  2. pick a hashtag it should search for (defaults to #starwars)
  3. 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":""}]
knolleary

Flow Info

created 1 month, 2 weeks ago

Node Types

Core
  • debug (x1)
  • function (x2)
  • http in (x1)
  • http response (x1)
  • inject (x1)
  • json (x1)
  • mongodb (x1)
  • mongodb in (x1)
  • mongodb out (x2)
  • sentiment (x1)
  • template (x2)
  • twitter in (x1)

Tags

  • twitter
  • mongo
  • sentiment
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option