I need a MongoDB database populated with some test data – a handful of small thumbnail images and a few other fields for development (so just junk/test data for the time being and weeks down the line I can populate with real business data). I have JIRA task with only one day allocated. On top of all of this, I know little, next to nothing, about MongoDB. I had better stop mucking around and get my head down. Now!
Step 1. Install MongoDB. Done. Well that was straight forward, and a download size just shy of 100MB to boot. I do not know what my expectations were but the binaries to install MySQL and Oracle are ca. 300MB and 3GB respectively.
Step 2. Watch the Pluralsight MongoDB database course. Wow! That was clear and concise and 2.5h of my time well invested.
Step 3. Generate a few thousand placeholder thumbnail images to populate into my MongoDB database that I will use solely for development purposes. For development, I will store the image as base64 (and the front-end browser or app can decode to display on-the-fly if/as necessary). Although leveraging GridFS is the obvious choice for larger (binary) file content, according to the MongoDB documentation, for small thumbnail images I intend to persist the base64 content directly within the database for now. Anything else at the moment is a bit heavyweight for my requirement. Storing directly within the database also greatly simplifies my database backup, replication, and distribution strategy, and these things are important when you do not know what you are doing!
For the thumbnails, although some random image would do, I want some identifying feature in the image file to enable me to visually confirm that I have the correct thumbnail image from any database query I might choose to execute. The obvious solution would be to have the image to contain a piece of text, such as a number. A quick Google search reveals lots of somebodies that have implemented this type of functionality online. I certainly do not wish to make a meal of this part of the task, so I intend to leverage their efforts. One somebody is Russell Heimlich. Using a few Unix shell commands, I can script up the rendering of a handful of base64 images containing a number using the offering exposed on Russell’s website.
Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ ls -la total 0 drwxr-xr-x 3 mdo staff 96 19 Okt 10:39 . drwx------+ 23 mdo staff 736 19 Okt 10:39 .. Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ for i in $(seq -f %04g 8000 8009) > do > curl "https://dummyimage.com/80x80/000/fff.jpg&text=${i}" | base64 > "${i}.jpg.b64" > done % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1804 100 1804 0 0 3648 0 --:--:-- --:--:-- --:--:-- 3644 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1678 100 1678 0 0 3355 0 --:--:-- --:--:-- --:--:-- 3356 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1778 100 1778 0 0 3757 0 --:--:-- --:--:-- --:--:-- 3751 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1782 100 1782 0 0 3776 0 --:--:-- --:--:-- --:--:-- 3783 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1743 100 1743 0 0 3428 0 --:--:-- --:--:-- --:--:-- 3424 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1775 100 1775 0 0 3811 0 --:--:-- --:--:-- --:--:-- 3817 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1805 100 1805 0 0 3643 0 --:--:-- --:--:-- --:--:-- 3639 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1699 100 1699 0 0 3584 0 --:--:-- --:--:-- --:--:-- 3591 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1835 100 1835 0 0 3777 0 --:--:-- --:--:-- --:--:-- 3775 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1809 100 1809 0 0 3662 0 --:--:-- --:--:-- --:--:-- 3669 Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ base64 -D 8007.jpg.b64 > 8007.jpg Michaels-MacBook-Pro:imgfiles mdo$ ls -la total 96 drwxr-xr-x 14 mdo staff 448 19 Okt 10:39 . drwx------+ 23 mdo staff 736 19 Okt 10:39 .. -rw-r--r-- 1 mdo staff 2409 19 Okt 11:26 8000.jpg.b64 -rw-r--r-- 1 mdo staff 2241 19 Okt 11:26 8001.jpg.b64 -rw-r--r-- 1 mdo staff 2373 19 Okt 11:26 8002.jpg.b64 -rw-r--r-- 1 mdo staff 2377 19 Okt 11:26 8003.jpg.b64 -rw-r--r-- 1 mdo staff 2325 19 Okt 11:26 8004.jpg.b64 -rw-r--r-- 1 mdo staff 2369 19 Okt 11:26 8005.jpg.b64 -rw-r--r-- 1 mdo staff 2409 19 Okt 11:26 8006.jpg.b64 -rw-r--r-- 1 mdo staff 1699 19 Okt 11:27 8007.jpg -rw-r--r-- 1 mdo staff 2269 19 Okt 11:26 8007.jpg.b64 -rw-r--r-- 1 mdo staff 2449 19 Okt 11:26 8008.jpg.b64 -rw-r--r-- 1 mdo staff 2413 19 Okt 11:26 8009.jpg.b64 Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ cat 8007.jpg.b64 | fold -w60 /9j/4AAQSkZJRgABAQEAYABgAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4w ICh1c2luZyBJSkcgSlBFRyB2ODApLCBkZWZhdWx0IHF1YWxpdHkK/9sAQwAI BgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3 KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIy MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AA EQgAUABQAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYH CAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQy gZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElK U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Sl pqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz 9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALUR AAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkj M1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFla Y2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKz tLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/a AAwDAQACEQMRAD8A+f6KKKACiiigAooooAKKKKACiiigAorX0fwtrevxSzab p8k0EJxJOSqRIeuC7EKD+NS6p4P1/RrL7be6c4s87Tcwuk0QPoXQlQfYmgDD oq1p2m32rX0dlp1pNdXUhwkUKFmP4Ctu98AeKLC0nuZdKZ4oAWmNvNHMYgOp YIxKgepFAHNUUV0tp8P/ABReWcN1HpTRxTjMP2iaOFpR6qrsCw9MDmgDmqKs 6hp17pN9LZahazWt1EcPFMhVl/A1t2PgHxPqVjDe2elPLbzLujcSoNw/FqAO borqz8NPGAVm/sSUhVLHEsZOAMno3pXKUAdz4kiu9R8CeGbrTBJLo1latBdR x8i3u/MdnZwOm5ShDHqBjtSfD5LqxGqareeZF4d+wXEF4XyI7hmjYRxD+8+8 qQByME8CrN3rE3w0lh0zQUSLWXs4pL/UJFEjBpYw4jjU5VVCuATgknPIHFS6 P4om+IGp2HhvxaEu/tJFrZ6gkYSe1duE+6AHTdgEEdCSCKAM6zmfw/8AC2W8 tW8q+1y+ezaVThhaxIrMgPYM7rn1C1zGjaxe6Dq1tqenTGK5t3DqR0PqpHdT 0I7iuo1uFv8AhVmhrwWsNWvbabDZw7LGw/RT+VcTQB6g/h3S0+M0n+iodFWA 6z5B+75XkeeEx6bvlx6V55q+rXuu6tc6nqM7T3Vw5d3Y/oPQDoB2Ar1Yjb8T rjRsYuf+EW/s4At/y1+wg4+vb6145QB29/M/iD4V22oXTebf6Lfiy85uWa2k Qsisep2srAegbFcRXY2C/Z/hDrUzj5bvV7WCM56lI5Xb8gw/MVzWkaZca1rF npdou64u5khjz0yxxk+3PNAHTacf+EY8Cz6wMLqWtl7KzOcNFbLxNIB/tHEY PoHrja6Xx3qUF94mltbF92m6Yi2Fl6eVF8u7/gTbn/4FXNUAdjLrfh/xLY2a +IjqFnqlrAlsL+ziSdZ40GE8yNmU7gMDcG5wMjvUum6x4X8IzjUtFfUdV1mM MLaa8t0t4LdiMeZsDuXYZ4BIAPPNcTRQB0nh7xJBZWV/o+s28t5o+oFXmWJw JYpVztljJ43DJBB4IODWhZy+BNEu11GObVtamiYPb2VxapbRbhyPNYOxYA9g Bn6VxdFAGsviXVE8Vf8ACSLcf8TP7V9q83GRvznp6dsenFbt3L4F1q7bUZZ9 W0aaZzJPZwWqXEQY8ny2LqVGegIOOnNcZRQB0XiXxBaaja2OkaPaS2mjWG8w pM4aWaRsbpZCONxwBgcADApvhHXLbw5qV1qUqTNdpZTR2JjAISd12B2yeAoZ jxk5Arn6KACiiigAooooAKKKKACiiigAooooAKKKKAP/2Q== Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$
Here is image 8007.jpg generated prior to base64 encoding above.
So far no rocket science!
Step 4. Load these base64 encoded thumbnail images, and a couple of other fields, into MongoDB. This is the hard part.
Here is the core code I wrote.
for (i=8000; i<=8009; i++) { var fb64 = cat(i + '.jpg.b64').trim(); var b = BinData(0, fb64); db.foo.save({_id:NumberInt(i), fileNumber: NumberInt(i-8000), someOtherField0: 0, someOtherField1: 1, img: b}); }
Here is the unadulterated audit log of what I executed using within the Mongo shell.
Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ mongo MongoDB shell version v3.4.9 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 3.4.9 Server has startup warnings: 2017-10-19T11:27:52.319+0100 I CONTROL [initandlisten] 2017-10-19T11:27:52.319+0100 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2017-10-19T11:27:52.319+0100 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2017-10-19T11:27:52.319+0100 I CONTROL [initandlisten] > show databases admin 0.000GB local 0.000GB > > > use mikedb switched to db mikedb > show databases admin 0.000GB local 0.000GB > > > for (i=8000; i<=8009; i++) {var fb64 = cat('i + '.jpg.b64').trim(); var b = BinData(0, fb64); db.foo.save({_id:NumberInt(i), fileNumber: NumberInt(i-8000), someOtherField0: 0, someOtherField1: 1, img: b}); } WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : 8009 }) > >
What! I thought what I had done above was supposed to be the hard part! This cannot be right, can it? I have created a new database, somehow (I switched to a new database named mikedb, that didn’t exist), I created a new collection (object foo, by adding to a collection that also didn’t exist). WTF! Let’s give this all a quick smoke test in step 5!
Step 5: Was it really all that painless?
Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ Michaels-MacBook-Pro:imgfiles mdo$ mongo MongoDB shell version v3.4.9 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 3.4.9 Server has startup warnings: 2017-10-19T11:38:52.319+0100 I CONTROL [initandlisten] 2017-10-19T11:38:52.319+0100 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2017-10-19T11:38:52.319+0100 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2017-10-19T11:38:52.319+0100 I CONTROL [initandlisten] > > > show databases admin 0.000GB local 0.000GB mikedb 0.000GB > db.getCollectionNames(); [ "foo" ] > > > > > db.foo.count() 10 > > > > db.foo.find({_id: 8007}).pretty() { "_id" : 8007, "fileNumber" : 7, "someOtherField0" : 0, "someOtherField1" : 1, "img" : BinData(0,"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") } > > > > db.foo.find({}, {_id:0, img:0}) { "fileNumber" : 0, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 1, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 2, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 3, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 4, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 5, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 6, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 7, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 8, "someOtherField0" : 0, "someOtherField1" : 1 } { "fileNumber" : 9, "someOtherField0" : 0, "someOtherField1" : 1 } > > >
Yes, it seems it was that painless.
I have spent a considerable portion of my IT career designing and maintaining performant normalized relation database systems. Spinning up a development system containing a bit of test data for development purposes, on a development machine, always takes time, sometimes a lot of time. There is the database installation (taking hundreds of MB if not GB of disk space), privs, schema creation, table creation and FK relationships, data constraints etc. On top of this, there is creating a data layer mapping the database rows into objects. None of this here – the database is created when the first object is added, the collection is created when the first object is added, the result set structure is simple JSON, and so on (and mapping from JSON to a C# class for example is … trivial!). Furthermore in one execution of the Mongo find(….) command shown above, did you notice that I specified content I wanted excluded from the database query? Compare that to SQL where … well that is just not possible; in SQL you specify the columns you want returned in the result set (included), or all columns, not the columnar content you wish to be excluded.
This is all quite humbling, especially as I am surrounded by others with demonstrable competency in this technology. To a seasoned NoSQL developer, nothing I have written above is a big deal or even surprising. I certainly need to learn more about MongoDB – this little experience has certainly whet my appetite for more. Furthermore I have completed my 1 day JIRA task, and it has only just passed lunchtime. What shall I do for the rest of the day? Perhaps the time to learn more about MongoDB is right now. I know I have only scratched the surface thus far!
— Published by Mike, 12:12:12 19 October 2017 (GMT)
By Month: November 2022, October 2022, August 2022, February 2021, January 2021, December 2020, November 2020, March 2019, September 2018, June 2018, May 2018, April 2018
Apple, C#, Databases, Faircom, General IT Rant, German, Informatics, LINQ, MongoDB, Oracle, Perl, PostgreSQL, SQL, SQL Server, Unit Testing, XML/XSLT
Simon Davidson
October 20th, 2017 at 9:43 am
Welcome to the dark side Mike