Database design and decisions used to be fairly straightforward.
Pick your relational database engine, map out the general entities,
apply the third normal form to them, and you're basically done.
With the Cambrian explosion of database options and variations created from about 2009 until present,
it's way harder to even choose the database,
much less follow the well-worn path of third normal form for modeling.
On this episode, you'll meet Rick Copeland, a fellow MongoDB master
and author of the book, MongoDB Applied Design Patterns.
We'll discuss modeling data using documents in a document database such as MongoDB
and some techniques and situations that apply particularly to MongoDB's implementation.
This is Talk Python to Me, episode 109, recorded April 26, 2017.
Welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the ecosystem,
and the personalities.
This is your host, Michael Kennedy.
Follow me on Twitter where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm
and follow the show on Twitter via at Talk Python.
This episode is brought to you by Advanced Digital and Hired.
Please check out what they're offering during their segments.
It helps support the show.
Rick, welcome to Talk Python.
Thanks for having me on, Michael.
Oh, I'm very excited to have you on.
Anytime I get to talk about MongoDB, it really makes me happy.
So we're going to have a lot of fun doing that.
And I think the work that you've done in MongoDB in a couple areas, in your ODM, as well as
your book that we're going to talk about, it's super work.
So I'm looking forward to sharing it with everyone and talking to you about it.
Awesome.
Yeah.
Well, of course, before we get into that, we've got to hear your story.
How did you get into programming in Python?
Well, so when I was, I don't know, when I was a kid, my dad got an Apple II, and I guess
that dates me a little bit.
But I learned how to program on BASIC starting there and then ended up just getting into
computer science in college.
So I was pretty hardcore in C, C++.
Out of college, I did some systems programming and various other types of things with visual,
C++, and ended up having a little period when I was exploring new programming languages and
I ran across an essay by Eric Raymond about why Python.
And it was kind of like his new favorite programming language.
And I'd seen a little bit of Python before, like I'd run across Gen 2 and I saw it's got
this crazy indentation syntax and I kind of dismissed it.
But then when someone credible...
This is a weird language.
It uses white space.
Let's keep going.
Yeah.
So when someone credible said, you know, this is really cool, I figured that I would get
into it.
And so I kind of taught myself Python, started to introduce it at that time into a enterprise
programming environment, which was interesting.
They were using mainly C# and Visual Basic.
It was kind of one of those things where whenever there was a problem and they needed something
solved really quick, I would say, oh, I'll use Python for that.
And they said, don't tell me what you're doing.
Just fix the problem.
So kind of flying it under the radar.
And then, you know, discovered that I really loved it.
So the next job, you know, I sought out Python programming positions after that.
I think I was in...
Python was around version 2.3 then.
So obviously it's grown a lot of new bells and whistles since then.
And just it's a lot more fun to program in even than it was then.
Yeah.
It's just both in terms of the language and whatnot, but also the ecosystem and all the
packages.
Right.
It just keeps getting cooler.
I think it's a fun place to be for sure.
Yeah.
Well, even back in, you know, 2002 or 2003 when I started doing Python, it was so far...
Like what you got when you just downloaded the standard library was so much more than you
got in any of the other languages that I was familiar with.
So, you know, if you wanted to do anything in C++, you had to go out and find something
that you would configure, make and make install.
And then, you know, you'd be able to get those development libraries.
But with Python, you know, you can download URLs, you can create an FTP server or, you know,
things like that.
And it's just built in.
So that was a nice aspect of the batteries included at that time.
Yeah, absolutely.
So what are you doing with Python these days?
What's your day job?
So these days I'm a consultant, which basically means I do kind of a little bit of everything.
So sometimes I'm out training different companies in how to do Python.
So I've been to D.C. and California in the last two weeks.
I sometimes do custom development for folks.
I've got, I think, three active projects going on for that.
And I'm working on a startup on the side.
So, you know, everybody's got to have their little side hustle that they want to eventually
make into something.
So I guess I've got more of a three side hustles going at this point.
Yeah, that sounds fun.
It's a challenge to do all these different things.
I know.
But it's also fun to have a wide variety and not just be doing the one thing, right?
Yes.
Yeah, it is.
It's never boring.
Sometimes it can be a little bit overwhelming.
Like, what am I supposed to work on today?
And the context, which can get a little bit much.
But, you know, it's all good.
Yeah, it's better than the alternative, I think.
Although you're right.
It's definitely overwhelming.
And you're still using MongoDB for some of these projects?
I am.
One of the things that I discovered is just it's kind of my go-to at this point.
I know most people, they learn relational databases because it's much more widespread use.
But I just kind of got used to using MongoDB.
In my last business, it was the main database of choice.
So, you know, I just, I have all the tooling and I have the familiarity with it.
So that's just the first thing I reach for when I'm implementing something for someone.
Yeah, I'm with you.
I feel like it just has so much more flexibility and whatnot.
I feel like a lot of people fall into using relational databases because that's considered the safe choice or that's what they already know or what they were taught in college.
Or like the people they're working with, they already know that, but it's not necessarily because it's the best choice.
Right.
Yes.
Yeah, absolutely.
So I thought maybe, you know, we're mostly going to focus on sort of advanced MongoDB design patterns and implementation concepts.
But not everybody listening to this is totally familiar with Mongo or NoSQL or document databases.
So maybe you could give us a quick view just into the summary of what is NoSQL?
What is a document database?
And I'm also interested to hear your thoughts on what is NoSQL because everybody seems to have a slightly different definition of that.
Okay, sure.
So I would say, you know, NoSQL is kind of anything besides SQL.
So if you want to kind of drop some of the constraints that SQL puts on you if you're programming.
So if you look at things like transactions, do you want them to be atomic, consistent, isolated, and durable?
If you drop some of those, then maybe you're in the NoSQL land.
So a lot of the NoSQL databases, well, I guess I should say they kind of run the gamut.
So a NoSQL database could be just a key value store.
So you're able to look up things very quickly.
It could be something that's more complicated, has an exotic model like Cassandra with a column, you know, column data store or MongoDB, which is a document data store.
So, and that's more like the storage model, the programming model, what are you actually putting into this database?
So I guess the, how I describe MongoDB is, or its document model is, if you think of the relational databases, you've got tables, which are made up of rows and columns.
In MongoDB, we don't call them tables, we call them collections.
And what you put in those collections are JSON objects.
So if you've done web programming, you've probably run into JSON.
So, and if you haven't, then it's Python dictionaries and lists embedded in each other.
Basically, that's the data model you're looking at.
So you just have a collection of these documents and, and we call them those JSON objects documents.
And you can kind of query into those collections.
So you can say, give me, say, all of the restaurants that are bakeries in this collection.
And so you have some field in each JSON document that says, you know, the type of cuisine and it's a, it's a bakery.
So you could do that sort of a query on a MongoDB database, which makes it a little bit different from a key value store because you don't have to just query based on the key of that document.
Right. Key value stores are like the most basic, fastest, most scalable, but also the most limiting, right?
Because you've got the key, the primary key, like an ID, or maybe you could use an email address or whatever if it's a user.
But then it makes it really hard to ask interesting questions.
Like the rest of the data is fairly an opaque blob.
I know there's ways to kind of like add extra stuff around some of the databases, but still.
Yeah.
Well, and a lot of the time, those things, you know, you have the key value store and then people will create their manual indexes around that.
So, you know, you've got kind of the natural key of something, maybe it's some restaurant ID and you want to look up things by cuisine.
So what you have is maybe a whole bunch of things in another collection that is like cuisine is the key.
So then those point to the restaurant ID.
So they build their own indexes out of these things.
MongoDB takes care of that for you in a lot of cases.
Right.
You know, one of the big distinctions, I think, that it takes people who are new to this idea of document databases.
And MongoDB is not the only one, just the most popular and probably the best.
But there's, you know, things like Azure DocumentDB, there's CouchDB, there's a variety of them.
Right.
And I think it's easy to look at these databases and go, oh, it's kind of like a JSON field embedded in another database or like storing a blob of data or something like that.
Right.
You're like, oh, I could do this and say Microsoft SQL server and just make like a text field or a JSON field and stick a blob in there.
But the big difference is you can index deep into these things.
You can do rich queries into them.
Right.
They're like, they're not just hierarchical things you can store.
But, you know, even look at some of the object databases, things like Zodb, things like that.
Right.
Yes.
So that is the big difference between this and a key value store, I would say, is that you can index into these things.
If you're using something like, like you could take MySQL and throw a, you know, a blob column and an ID column into a table and call it a NoSQL database if you want to.
But you don't really get the ability to do these sorts of rapid lookups on something other than the key.
And that's what MongoDB gives you.
That plus it gives you some scaling advantages as well.
But my background, I haven't taken advantage of that as much as I've just taken advantage of the fact that you can do reasonable things very quickly as opposed to doing unreasonable things reasonably quickly.
Right.
I think that's a really interesting comment you made about the performance.
Right.
Like one of the things you can do with a lot of these NoSQL databases, Mongo included, is you can do lots of replication.
You can do specifically, I'm thinking of like sharding, like I could set up a 10 sharded cluster.
And so then when we do inserts, they're like crazy fast and we can parallelize our queries and our aggregation and MapReduce stuff, all those kinds of things.
Right.
But that is like the thing that draws people to it.
They're like, oh, look what we can do with performance.
But at the same time, like very few people actually end up needing that much performance.
I mean, I've seen a few places where it was really needed, but 99% or more of the use cases don't.
But everybody has a, my relational schema is a pain to deal with.
It's hard to add columns.
It's hard to change the shape of it.
It's like a pain.
It's slowing me down.
It's have a, everybody has a complexity problem with their software.
And I feel like modeling in these documents solves that complexity problem for everyone, not just the 1%.
Right.
To me, the sharding and the ability to scale out horizontally has always been kind of a safety feature.
Like if things go really super well, my system's not going to fall over and I'm not going to have to come back and do manual sharding or partitioning in my database and re-architect my whole application.
I know that there is a path forward if something like that happens.
But for now, I can get things done faster than I could with any of the relational approaches.
Right.
Yeah.
I totally agree.
Totally agree.
So one of the, there's a bunch of different ways to access MongoDB from Python, right?
You've got the official Python driver, PyMongo from the MongoDB folks.
You've got this new thing, BSON, NumPy, NumPy, BSON.
I don't remember the order of it that goes straight into the data science type structures in NumPy.
And then on top of PyMongo, we've got things like MongoEngine, Ming, MongoKit, and all these ODMs, right?
Right.
And one of these, named Ming, actually, is one that you created.
Yes.
Maybe give us a quick overview of what are the trade-offs?
When would you consider using one of these ODMs?
Like, what the heck is an ODM anyway?
So it really comes down to the idea.
So I said we don't have tables.
And one of the other things that you don't really have when you're dealing with MongoDB is you don't have a database-enforced schema.
So you have, it's kind of like this big bag of things.
And I said that, you know, they're kind of like Python dictionaries.
So I'll have to say this very quickly or very carefully.
But you don't want to end up with a big bag of dicts when you're working on this.
So what you need to actually have is some sort of a schema that tells you the sorts of things that you're going to put in these collections.
Because it turns out whatever you're putting into them, when you read them back out, your code's going to have to do something with that data.
You can't just say, well, I'm just going to store everything in there and it's magically going to reappear.
Your code is making certain assumptions about what fields are in those dictionaries, what keys, and, like, what is the structure of the data that you're storing?
So that's really what these ODMs or object document managers do.
That tells you, you know, in this collection, we're putting things in that look like this restaurant.
So although MongoDB, until very recently, didn't have any form of enforcing schemas, this would be something in your code where you're documenting it.
At the very least, you're documenting what sorts of dictionaries or BSON documents you want to be putting into these collections.
Right, and so these, if you go through one of these ODMs, object data mappers, layers, you basically go through predefined classes and objects in Python, which themselves have a fixed structure.
And so you're kind of, you filter through, like, a known layer of schema, and that works pretty well, right?
Yeah, yeah.
And that allows you to kind of, you can get a long way without having any kind of a documented schema if you're the only programmer on the project.
But once you start having multiple people, you need to have kind of a common understanding of, well, I'm going to write things that look like this to the collection, and I'm going to read things and expect them to look like this other thing.
So that's kind of the base level of why you need something like this.
You need a library or a data access layer.
Sometimes people will write their own.
That's a pretty common thing.
If you don't use an ODM, then people will typically write Python modules that have, you know, getters and setters for different types of data that they want to put into the database.
That's the approach that MongoDB uses on their training materials, I think.
They just build this Python module that does these things.
So an object document mapper allows you to kind of abstract that out and write those more quickly.
So rather than saying, you know, I want to get a restaurant or I want to write a function that calls, you know, this is called get restaurant, then I can have a restaurant class that has a get method.
But the get method is not something I have to write.
It's something that the ODM provides me.
I hope that makes sense.
Yeah, I think it does.
And a lot of these, I can't speak to me, you'll have to fill us in on the details.
I don't remember exactly.
But the one that I'm using right now is called Mongo Engine, which is also one of the more popular ones.
And it has a lot of additional things that it helps you with.
Like you define a class and it's much like SQLAlchemy.
You say these are the fields that go into the database.
And this one's a string and it has to be unique.
Like this one's an integer and I want an index on it and things like that.
And so it'll actually apply the uniqueness constraints.
It'll apply the index.
It'll create and enforce the indexes, all those sorts of things as well.
That's part of what Ming does.
Definitely.
You can put these constraints in there, these indexes that you want it to define, and it'll go ahead and create those indexes for you.
Another thing that it's helpful or that it helps you with is your schema evolves as you're building your application.
So maybe you didn't need a zip code when you first started or you forgot that you were going to need a zip code.
And maybe that's a bad example.
But there's some fields that you want to add later on and you need a sensible default for the existing documents.
Like let's say you have an account class and you eventually want to start verifying that they've verified their email address.
And you didn't think of that at first.
You don't have a is email verified or something like that, right?
Yeah.
So maybe you want all of the existing documents to have that be default false.
They haven't verified their email.
So you can write a validator or a type into your schema that says, you know, when this field is not found, then I want you to populate the Python object with false.
It helps you to do these sorts of on-the-fly data migrations.
Right.
And it can be kind of like you describe it in your book as a lazy, lazy migrations or lazy schema migrations.
Because in a relational database, that wouldn't fly very well, right?
You'd have to say, well, we're going to have we're going to do a schema transformation and we're going to add a column and it's going to be a type bool and it's going to be default.
There's some kind of script you got to run probably.
Yeah.
And those I guess that's the deal.
You when you're going to be changing the schema in a in a SQL database, you do it up front.
So you've got to make sure that all of the rows conform to the schema.
And, you know, the database is going to enforce that.
So you do this alter table statement and it makes sure that everything conforms to it.
So that's one approach.
And you can do that in MongoDB as well.
You just go in and you and you overwrite all of the existing documents.
Right.
It's maybe as in a SQL script.
It's just a JavaScript script or something like that.
Right.
And you run that.
Yeah.
Mongo gives you the option of kind of waiting until you actually load a particular document to make sure it conforms to your current schema.
So that's something that we built into Ming as well so that you could actually like read a document and then check to see does that document actually conform to my current schema.
And if it doesn't, there was actually the ability to fall back and run a migration function on that document.
So you could actually bring things forward at the moment when they're loaded out of the database.
Oh, yeah.
That's really cool.
So one of the early success stories from MongoDB, I think, comes from SourceForge, actually.
And you were part of this.
I remember SourceForge.
This is before there's a GitHub or anything like this, right?
And SourceForge was used quite frequently.
And I remember it was getting painfully slow.
And then one day it was fast again.
And you were involved in that somewhat.
And that's actually partly where Ming came from, right?
Do you want to tell us about that?
Yeah.
So when I came to SourceForge, I remember in the interview when I was about to come to SourceForge, I had worked on building a SQLAlchemy-like library for, I guess you could call it a NoSQL database.
It was a private thing that the company that I was working for had developed internally.
And so they asked me about that.
And they said, well, you know, we've got this thing called MongoDB that we're thinking about working on.
And it kind of stores Python dictionaries.
So what would your approach be to doing something like that?
And so, you know, I kind of talked about it.
And I guess my answer was good enough.
And they hired me.
And they said, you know, we did some performance evaluations.
And at that time, it was like 2009.
They looked at various different approaches.
And they said, MongoDB is going to give us the performance that we need.
And we're comfortable with the data model.
So we like the idea of storing things that look like Python dictionaries into the database.
But we would like to have something like some kind of a schema enforcement layer or an ODM.
Although I don't know that that was really a big term at that point.
They maybe called it an ORM even.
Yeah.
I call it an ORM for a non-relational database.
Yeah.
ORM minus the R.
Yes.
So, you know, we started working on that.
And I was the main developer on Ming.
And so Ming formed kind of the data layer of a complete rewrite of all of the SourceForge developer tools.
So when you think about SourceForge, there's kind of two sections of it.
I mean, if you think about SourceForge these days.
But there's sort of the, this is the site for the developers to build their software.
And this is the site for users to download software.
This portion of Talk Python is brought to you by Advanced Digital.
How would you like to build one of the most visited news sites in the U.S.?
That sounds fun.
The folks at Advanced Digital would love to talk to you.
They're primarily a Python shop located in beautiful Jersey City.
Just one subway stop from lower Manhattan.
Spend your time building an amazing web app with Python.
And do it with a small team of developers focused on agile development.
Are you going to miss PyCon this year because your company wouldn't fund the travel and expense?
If you join this team, they'll cover your conference and training initiatives.
It's time to take your Python to the next level.
Build an amazing web app.
Get started by visiting python.advance.net right now.
So we rewrote kind of all of the developer tools.
And we rewrote a lot of the download side of things as well.
And that was actually a migration from PHP to Python.
And a migration from largely Postgres backed to mostly MongoDB.
And we kind of did it in stages.
But Ming was a big part of that.
Being able to kind of come in and say, we've got a group of programmers working.
What's our common understanding of the data that we're storing in this weird database that none of us has seen before?
Right.
And how did it go?
I recall that there were some pretty major stats in how much better the site got.
How much fewer, how many fewer database servers there were?
Things like that.
Do you recall?
Well, I remember we went from handling, it was something like 13 servers that were running the PHP front end.
Our first deployment, we went down to, I believe, four Python servers doing basically the same work.
So that was a nice, nice thing for Python.
And of course, the PHP was backed by Postgres and the Python was backed by Mongo.
And one of the other things in the first version, this is what a lot of people did with Mongo at the time, and I guess still probably do, is when you're introducing this new technology, you kind of take baby steps.
So Mongo was not our system of record initially.
We would use it as kind of a cache for all of the Postgres data that was coming from the legacy system.
So all of that went into Mongo.
And then as long as you obey a few little rules like make sure your working set fits into RAM, Mongo behaved, its performance was closer to memcached than it was to a relational database.
So, you know, super fast for a read mostly workload.
And that's why we were able to do nice things.
And then we, like a lot of people who first deploy MongoDB, we think, oh, this is great.
It can probably do anything I want it to do.
So we wrote a little rate limiter in MongoDB.
And we did it in a really stupid way, it turns out, by basically just logging every request.
And then every time a request comes in, we would query to see how many requests from that IP in the last X seconds or minutes or whatever a rate limit was.
And that worked until it didn't, which was when the index got bigger than our RAM.
And you got this nice cliff of performance.
So we reworked that.
But, you know, for the most part, it was a pretty good rollout.
And, you know, a lot of success moving from PHP to Python.
And there's still things that run on.
Last I heard, there were still things that ran on Postgres at SourceForge.
But it was primarily MongoDB later on.
Yeah, okay.
That makes a lot of sense.
That's really cool.
Is it still running in Mongo, do you think?
Do you know?
Well, it is.
So the first version that we rolled out was only for the download side.
And then we ended up rewriting all of the developer tools in Python and MongoDB.
And then that ended up being outsourced, not outsourced, open sourced as the Apache Allura project.
So it's now an official Apache Software Foundation project.
And anybody can run the same tools that SourceForge is running for developing software.
And there's a little bit of setup involved.
But it's still out there.
It's something that was kind of a goal early on that we wanted to make sure that we gave back to the community with what we were doing.
And, of course, Ming was always open source from the beginning.
SourceForge has had its moments of evil, but generally has been a good supporter of open source software.
Yeah, I say historically, it's probably got a positive grade, all in all.
Yeah.
All right.
So one of the things I really want to dig into while we're talking is your book called MongoDB Applied Design Patterns.
But before we get to that, I just want to quickly write an idea by you and maybe make a plea to anyone who is either running or considering running Mongo.
I think I'd love to hear your opinion.
One of the things, I think Mongo is super great, but I think they've made a few fairly minor decisions that have come back to haunt them in certain ways that get amplified from the early days.
And I think one of those is, by default, not running encrypted connections.
And another is, by default, not running with authentication.
Yes.
So their defaults have always been interesting.
Maybe I'll use that word.
I think they've optimized too much for performance and scalability and not enough for durability and safety nets.
I'm thinking of the initial write concern defaults.
I'm thinking of the lack of journaling in the early days.
You know, all these things.
And each one of them maybe made sense in their original world.
But I think people have taken these and not knowing they need to be aware of them got themselves in trouble.
Absolutely.
So when we started out, the default way that you wrote to MongoDB, if you didn't change any of the settings and you do an update or an insert or whatever, basically you got an acknowledgement from the server that, hey, I received your request to write this data to the database.
What you didn't have was any assurance that it actually made it onto disk.
We didn't even get an acknowledgement.
Yeah.
Not even into the data set and memory.
Just the servers received your socket request, basically.
I think we even didn't get that initially.
Yeah, I think you might be right.
Yeah, you could be right about that.
So everybody learned, first of all, that you needed to have this magic argument when you connected called safe equals true.
So by default, MongoDB was running an unsafe mode, which is kind of a silly thing to do when you think about it.
It's cool.
It's fast.
Yeah, it was certainly fast.
And somebody made a nice web video about web scaleness from that.
Dev null is very fast, too.
Yeah.
I can write an infinite amount of data to it super quick.
But so everybody, you know, we moved over to safe equals true.
But even then, you just got an acknowledgement that server received your request and maybe it didn't violate any unique key constraints.
So, okay, great.
That's some progress, but it might not make it to disk.
And so they told you, well, you need to really run in replication.
So then you could get some, you could say, well, I want to only consider my right to be complete once it's been also written to another server.
Okay, fine.
Well, that's pretty good.
That's if you're actually getting verification of replication, then you're probably running in a slightly safer mode than most people are writing to MySQL.
So I would say that's a good place to be.
But then they've also got this network issue that by default, you get MongoDB, you fire it up, and it's going to bind to all of the IP addresses on the machine with no authentication and no encryption.
And anybody can connect to it, read, write any of the data that's on the database.
So that is not really a good default state to be in.
And it turns out a lot of people didn't read their docs when they moved to production.
And there was a big exploit recently where there were thousands of production MongoDB databases that were compromised because they were running completely wide open to the intranet.
So, yeah, be careful.
Yeah, absolutely.
So basically, I bring this up for two reasons.
One is there's a lot of FUD about Mongo involving things about this write concern and the journaling, and all those are changed, right?
The defaults are to do the right thing these days.
So those are basically phased out.
But this last thing about the security is not.
If I were king of Mongo, I'm not a king of MongoDB.
But if I were, I would make it a change that unless you set up authentication, it will only listen on localhost by default.
Right.
That would be my rule.
And that's kind of safe.
Like, if you're running the server next to your web app or for dev, it's fine.
And if you want to do something production-wise, you've got to configure it a little better.
But that's not how it works.
So just if you guys are listening and you want to run Mongo, definitely, we both definitely recommend it.
Just make sure you turn on security or you don't listen.
Just unprotected on the internet, right?
Just take a few steps to enable encryption if you're going to go across networks and security authentication, things like that.
Yeah.
And I think the latest versions of the RPMs and the Debian packages do bind only to the local host.
So at least they're a little bit more secure.
But still, if you're just running the MongoDB binary by default, it's going to listen to anything.
So, yeah, be careful.
Yep.
And that also, it's not just a server production thing, right?
Like, that could be a dev issue.
Your dev machine could be on the network and you could be running a dev version with live data and it could have the same problem.
So just be careful about this.
Yes.
All right.
So let's talk about your book, MongoDB Applied Design Patterns.
That's the title, right?
Yes.
Okay.
I didn't copy.
It's not a paraphrasing.
Okay, good.
So this is a book that looks at MongoDB from a Python developer's perspective.
And really, I think it's a super book.
The idea is to look at a bunch of different use cases and challenges and try to solve them, right?
Right.
The genesis of the book is MongoDB needed to, or they wanted to have something like a list of different use cases.
Like, how do you use MongoDB in this situation?
And so I wrote up a bunch of use cases for them and then they said, you know, this would be a really good book.
So let's see if we can introduce you to some people at O'Reilly and see if we can kind of flesh these out into a full O'Reilly title.
And so that's what we ended up doing.
Yeah.
And that book came out in 2013, right?
Sounds right.
Yeah.
And MongoDB 2.
Something 2.2, 2.4 sort of time zone.
How much of it do you think is still current?
And how much do you think is sort of slightly changed with a release like, say, MongoDB 3?
There are definitely changes to some of the performance concerns that have to do with the way that the storage engine works since version 3.
Because they switched to WiredTiger by default and not mem map files, yeah?
Yeah.
So the nice thing, nice maybe in quotes here, for programming against MongoDB in the olden days before WiredTiger is it was really easy to understand the memory model.
Because what they did is they just took your whole database and they mapped it into RAM.
And they used the Linux virtual memory system to decide what was in and what was out.
So if you know how to modify memory, then you knew the most efficient way to modify MongoDB.
With WiredTiger, that's changed.
They have a real storage engine.
You know, it has multi-version concurrency control.
It has some interesting, interesting in a good way, performance characteristics of being able to, you know, have multiple writers going at the same time.
So I would say some of the things that really optimized for in-place modification in my book don't really apply as much.
Because there was a huge difference in performance in the old storage engine between writing to something in place on the disk and doing something that, say, changed the size of a document and required MongoDB to write a whole new copy of the document somewhere else on the disk.
Right.
And the way it works now, it's totally different.
So, all right.
But my look, when I went through it, I felt like this is really still quite current.
I think you're right about probably the considerations around the memory map files and whatnot.
But other than that, it looked really good.
So let me read a really quick excerpt from the book just to kind of set the stage.
So you say, traditionally, relational databases, while familiar, present significant challenges and complications when trying to scale up to big data needs.
And into this world steps MongoDB to address the scaling.
And around all of this height and excitement, a bunch of sites grabbed a NoSQL database, MongoDB database, and threw it out there and just started working with it without really understanding that it takes a different thinking about it.
Right.
It's paraphrasing.
Right.
But it's basically – and some of these things we just talked about around the durability and security were one of the things.
But I think more – probably the biggest mind shift that you have to make in this world, and you start – you dedicate a significant part of your book to this right at the beginning, and I think you should, is schema design and document design relative to, say, first normal form and third normal form and all that.
Yes.
So I would say that the biggest mindset shift that you've got to get through to be effective at MongoDB schema design is to say how you – what happens when you get rid of joins and what happens when you get rid of transactions.
So it's kind of the reads and writes.
So MongoDB does not support the join operator.
Well, there's a way to do it in the aggregation framework.
But besides putting that aside, generally, when you do a query in MongoDB, you can get a collection of – or you can get a set of documents in your results set, but you're not going to be talking to two different collections when you do that.
You're going to be making a query against a single collection.
And you'll get documents from that single collection.
And so the question is, how do you actually use that in an efficient way?
So if I was building a blog in a relational database, then maybe if I need to render that blog post, I would maybe fetch something from the posts collection.
I would fetch something from the authors collection.
I would fetch something from – or not collection, but the post table, the authors table, comments table.
And I'd do a join of all these things, and you'd end up with all of the data that you need to represent that blog post to a web user.
Well, with MongoDB, you can do the same thing.
You could have a posts collection and a comments collection and an authors collection, and you can do kind of the join-y work in memory.
But you've gotten rid of a lot of the benefits of MongoDB because the nice thing about MongoDB is you can design your schema so that a single document can satisfy that web request.
So you could have the post with the embedded author information with all of the comments all in a single document.
So basically, you're doing a single fetch, a single round trip to the database.
And even on the database, if you're using a disk or you're using an SSD, whatever the case is, you've got all the locality right there.
So the whole document is right where Mongo is looking at that time.
And so it's able to basically just do things much more efficiently if you design your schema right.
Yeah, and I think it's very much a Shakespearean type of thing, like to embed or not to embed.
That is the question, right?
Like really, every time I sat down to design a new data model for MongoDB, it's like, what are all the pieces?
What embeds where and what shouldn't be embedded for various reasons, right?
So like, for example, you mentioned you could have your post and it could have the author embedded and it could have the comments embedded and so on.
Maybe even there's categories, right?
Like categories and things that you could theoretically embed the category data into the post, but then you have to replicate that across all the different posts, right?
Sure.
Yes.
That may or may not be something you want.
Yeah.
So you still have relationships in your data.
That's a logical concern, right?
You can do an entity relationship diagram and you can still map that onto MongoDB.
The difference is with Mongo, when you have one of these one-to-many relationships, all of a sudden you now have the option, if it makes sense performance-wise, that you could take both of the entities and put them into a single collection.
But you can't do that in a relational database, right?
Relational kind of first normal form says you don't have multiple entries in a column.
But with MongoDB, that's sort of the norm.
You're allowed to have these array types that are being stored there.
So now you've got to decide, does it make sense to put it there?
Or if you've got a many-to-many joint or a many-to-many relationship, the old way of doing it or the SQL way of doing it is you've got to have a join table that's got IDs from table one and IDs from table two.
And it tells you which ones match up with which ones.
MongoDB, if you're doing a blog, again, it's just an easy example.
So you've got tags or categories.
A lot of the time, that'll just be a list of strings that you put into the post.
And there's no need to actually have that join collection or that join table that you would have in SQL.
I think that's totally right.
And even if your tag thing was more complicated, right, you can do these many, many relationships and maybe store a list of tag IDs in every post.
Right.
And then reach back into the other table.
Yeah.
You'd almost never want to have something like a join table in MongoDB.
I can't think of a good case.
You'll almost always want to either have a list of IDs in collection A or a list of IDs in collection B or both.
But you wouldn't want to have a separate collection where the existence of a document means that these other two documents are joined.
Yeah.
I find that to be almost never.
I don't think I've ever seen that in a well-designed case either.
I definitely have never made use of it in the apps that I built.
That was one of the problems with people coming from the SQL world is they know how to model things there.
And they just assume that if I take the same schema that I had in SQL, it's going to be like that but faster if I do it in MongoDB.
Yeah.
Because I heard Mongo is faster.
So it'll be faster if I just put this over here.
Exactly.
Yeah.
It probably is faster, but not because you copied over your schema design from a relational database.
Yeah.
Or in many cases, it would end up being slower because you're doing all of the logic of the join at that point, but you're doing it in whatever your programming language is.
So I love Python, but it's not this super high-performance bare metal language.
If you're building a join engine in Python, yeah, you can do that.
But you are now talking about introducing network latency to talk to the database.
You're talking about it's written in Python.
It's not written in C++ like the MongoDB engine is or like C database engines might be in other cases.
So you're kind of, if it's faster, then it's an unusual situation.
You're usually going to kill yourself performance-wise.
This portion of Talk Python to Me is brought to you by Hired.
Hired is the platform for top Python developer jobs.
Create your profile and instantly get access to thousands of companies who will compete to work with you.
Take it from one of Hired's users who recently got a job and said,
I had my first offer within four days and I ended up getting eight offers in total.
I've worked with recruiters in the past, but they were pretty hit and miss.
I tried LinkedIn, but I found Hired to be the best.
I really like knowing the salary up front and privacy was also a huge seller for me.
Well, that sounds pretty awesome, doesn't it?
But wait until you hear about the signing bonus.
Everyone who accepts a job from Hired gets a $300 signing bonus.
And as Talk Python listeners, it gets even sweeter.
Use the link talkpython.fm/Hired and Hired will double the signing bonus to $600.
Opportunity is knocking.
Visit talkpython.fm/Hired and answer the door.
Yeah.
So one of the things while we're on this document design stuff is in MongoDB, there's no concept of a foreign key constraint or relationship.
Right.
I can't have one document with a strict relationship to another document.
Right.
I'm not really sure how much value you get.
There's no joins and things like that.
Like, so oftentimes people think that means there's no relationships in MongoDB.
Right.
Yeah.
But I don't think that that's true.
I think you can put them into these models.
They just don't span documents, right?
Right.
Yeah.
You can have, you know, the relationships can exist within a document and you get atomic updates and things like that.
So you get the database to enforce some consistency there.
And you can also model the relationships with, I mean, it's not enforced by Mongo, but you can have a foreign key concept where you've got an ID of a different document in another collection and you're storing that ID.
Differences that you always have to take into account the possibility that that document might not actually exist.
That's right.
Yeah.
I think of them as two things.
I have a slightly different name that I've used over the years for it.
Like for the stuff that's within your document, you've got a post and it has a list inside of it of comments.
Like that is a super strong relationship.
You can't have a comment without the post.
It is the same thing.
But if you were like reaching back to an author table through just a foreign key constraint, that doesn't really exist, but it's logically there.
I call those soft foreign keys or something like that.
Like they're not enforced, but they technically, they fill the same role, right?
Yeah.
They fill the same role.
And sometimes people call them references or document references.
Way back when I started with MongoDB, one of the patterns that they kind of promoted was storing the collection name along with the ID.
I never found that super valuable, but that's another thing that you can do.
If you want to have a reference that could go to any collection, then you can just throw the collection name in there.
Yeah.
Interesting.
That works well at the low level, at like the PyMongo level.
Less good at the ODM level.
Right.
So let's talk about some of the use cases.
So we've kind of set up this, you talk a lot about like, this is what modeling in this world looks like.
You also talk about mimicking transactional behavior with compensation models that work well in MongoDB.
But let's just kind of leave that as there.
So you kind of set the ground with some of these foundational things.
And then you say, let's talk about six different use cases, all the performance considerations and how you model it and everything.
Right.
So do you want to touch on some of your favorite ones there and maybe like what was non-obvious or maybe something like that?
Yeah.
So the first one is, has some of the more interesting parts, I think, or some of the things that I found really interesting.
And I guess that's why I put it first, but that's the operational intelligence chapter.
And it's really focusing on analytics and dealing with kind of high volume data that's coming in quickly.
There were two different use cases in there, or maybe there were three in there.
But two in particular that I remember were, one of them was incremental aggregation.
So this is, you've got something coming in, you've got these aggregate statistics that you want to report out immediately.
So one approach that you could do for aggregation is you can run a big MapReduce job on a Hadoop cluster, and that'll come back in a few minutes.
But if you actually want something that's up to the minute, then how do you do that in an efficient way?
And so this relied a lot on the in-place updating, and it was based on MongoDB's own, it's not called Cloud Manager, but their monitoring service, which would actually monitor MongoDB performance for you.
And they offered this as a free service.
So it was like, how do we deal with this scale?
So let me show you how you can build your schema to deal with that kind of scale and how you can keep the performance high, even with an in-map storage engine.
No, I just, I think it was, what I found interesting about this was you start from, like, let's start with log file data, like something out of Apache web request or something like that.
Let's put that in the database.
And then let's start doing, like, processing and analysis of it.
And you have some really interesting graphs and various things that say, like, let's look at, if we design it this way, what are the trade-offs?
What is the benefits, what are the drawbacks?
And there was a number of non-obvious ways in which things kind of slowed down or got out of control.
And you ended up with quite an interesting aggregation report database, right, where you pre-computed and pre-allocated a whole bunch of pieces and then used some of the in-place update operations to sort of, like, increment the numbers at the right levels as these things came in, right?
Yeah, that was the incremental aggregation one.
So that was, the problem there is it was storing the aggregates in these large documents.
And sometimes the documents would grow and that would cause performance problems.
And then you get into a secondary issue, which is that even though you think of these things as Python dictionaries, which are super fast to access any item in them, physically they're stored as a list of key value pairs on the disk.
And so it turns out it takes longer to access something towards the end than it does to take to access something towards the beginning.
So how can we mitigate that issue?
And those were just some sort of the sorts of things that you can only see when you've actually run some performance metrics against it.
Again, just a shout out to Python.
I did all this with, at that time, IPython notebook and printed out the graphs and, you know, just threw those into the book right there.
So I think those are actually screenshots from IPython, now Jupyter notebook.
Yeah, they looked like some Matplotlib graphs or something, which is cool.
Yeah.
All right.
So another thing that people, at least in the early days, were like, oh, you can't use MongoDB for this was e-commerce, which I totally disagree with that statement.
But you have a section where you talk about using MongoDB for like an e-commerce site, right?
Yeah.
So one of the big things or one of the difficulties with existing e-commerce, I guess the big one is Magento.
So Magento uses an entity attribute value store.
So they're still stuck on SQL, but they use SQL in a way that makes it non-relational.
Basically, instead of keeping your products in a products table where each one of the attributes of that product is a column, they just say, I've got one big table that says for this entity, maybe it's a shirt.
I have an attribute, which is a size, and it's an Excel.
For this entity, which is a drill, it has, you know, some other attribute, and it's, you know, 120 volts or whatever.
And so out of that, they're able to get this very flexible schema.
So it's kind of like, well, that's not really a fantastic way to map to the relational model.
But they kind of have to because you want to deploy to a store that might have all sorts of different items in it that have different attributes that you want to store.
Nice thing about MongoDB is not all of your documents have to look like each other inside the collection.
So Mongo lets you actually say, well, I want to store drills and shirts in this collection.
Can I do that?
And it turns out you can.
Maybe there's certain attributes that they all have in common.
They have an SKU number.
They have a price.
They have maybe a quantity available.
But then they've all, you know, got their other things that are custom to each one.
And so you can introduce this polymorphism with MongoDB in a much more natural way, I think, than using something like an entity attribute value schema in a relational database.
Yeah, I think that's leveraging a pretty interesting aspect.
And you're in some sense implementing inheritance for specialization.
Not exactly, but something to that effect, right?
And that because the schema is really enforced at the application layer, not in the database layer, that flexibility pretty much just flows through.
And you end up with these sparse objects.
Like maybe one document has a drill bit size or something.
The other one has a shirt size, right?
And those don't appear in both records.
You don't waste the space.
Yeah, exactly.
And you can build your ODM to kind of take care of that.
I don't think I haven't been doing a lot with Ming super recently, but I'm not sure if we had the ability to kind of discriminate based on the data that it loads out as to which physical type of object it's creating.
But that's certainly something that you can do with an ODM.
And I know it's something that SQLAlchemy does with relational databases, but it requires you to either do a super complex schema in SQL or it requires you to waste a lot of columns.
And those are kind of your two options to do this sort of object oriented polymorphism.
Nice.
So what are some of the other ones that you cover that you really like?
So I did have some fun with the online gaming chapter because that was just, I don't know, games are fun, but kind of like brainstorming out like what are some of the data structures that you might need when you're building this?
How do you do these in a, say, it's a massively multiplayer online game?
How would you actually store this?
How would you scale it?
How would you do the sharding?
The online advertising networks was also interesting just because it's a very high frequency sort of application.
And it's something that I had seen a little bit of at SourceForge.
And, you know, one of the things that you mentioned earlier on was, you know, SourceForge got slower and slower and slower.
So part of that we can blame on maybe PHP and Postgres, but part of it we just have to blame on the ad networks.
Because SourceForge is an advertising supported site, a lot of these ad networks just took a long time to render the ad.
And that's kind of slowing down your browsing experience and can cause various other problems.
So what if we could speed those things up and deliver contextual advertising to people in a way that doesn't make them want to pull their hair out?
So that was also an interesting one.
Yeah, that's a fun one to work on.
And I know a couple of people working in this ad network space and they're using Mongo and they have some pretty intense requirements around the traffic that they handle.
Because if you run ads on a site that gets, you know, a million views a day and that's just one of the places, right?
You all of a sudden are getting a million requests a day.
You're getting a million requests a day and you're trying to target those ads now based on some content, you know, that's going on in the article.
So presumably you've indexed that and you know something about the keywords, but then you probably have some real-time bidding going on for those too.
So how do you actually choose the ad inside that request-response cycle?
Because you know that your content people that are actually paying or that, you know, you're advertising on their site, they're not going to like it if you slow down the experience for their viewers.
No, absolutely not.
So, yeah, that's definitely a cool example.
So there was a bunch of great examples and I learned a lot from looking at how you implemented them and the trade-offs.
And it's a great book.
I definitely recommend if people are, they know a little bit of Mongo and they're like, I think I should be using this, but I don't really know how to solve this problem.
There's a lot of good stuff to study there around schema design and whatnot.
Well, thanks.
Yeah, you bet.
So there's a couple of options on where you might run your MongoDB server.
And I guess it depends on how complicated of a situation you have.
on how much you want to think about this or need to think about this.
If you're just running a single server and it's just like there on a machine, maybe you can run that on a VM.
You still got to deal with backups and whatnot.
But there's also like hosted Mongo.
They have MongoDB Atlas.
What are your thoughts on like if somebody comes to you and says, hey, I want to do the site and run maybe let's say a three node replicated cluster?
Like what would you consider?
I would, by default, I would hope that their budget would afford them to get Atlas.
So Atlas is actually the cloud service by MongoDB.
They'll host your Mongo for you.
They'll host the latest copy or the latest version, handle your backups and everything.
Now, if you're dealing with a large amount of data, the backups can start to get pretty pricey.
So that might not be an option.
But unless you have strong operations people on your team, I wouldn't immediately jump to saying, oh, I need to self-host.
I need to build it.
I need to run it on my own VMs.
So there's other options that you can go to.
You can go to ImLab is one that I've used in the past.
I've really enjoyed working with them.
They provide, you know, hosted MongoDB, Compose.io, Object Rocket.
These are all hosted MongoDB options that you can go with.
And then if you are going to decide to self-host, there's actually some MongoDB provided tools to do that.
So if you actually go into the MongoDB Cloud Manager, provide them your EC2 account keys, for instance, and you say, I want to use these three servers or these three virtual machines that I've provisioned to make a three node replica set, then they can do that for you as well.
So that would probably be, you know, the next step is get your own VM or get your own VMs and then install Cloud Manager and go ahead and have Cloud Manager install that.
Okay, cool.
And the Cloud Manager, that's from MongoDB themselves?
Yeah, that's also from MongoDB.
So all of these things kind of run in the same UI on MongoDB.
I guess it's .com.
I know they have .com and .org both.
Yep.
That used to be a big confusion.
You couldn't find the download link on .com.
Yeah.
One thing I'd like to say is I have used MongoLab before, MLab.
It used to be MongoLab.
They renamed it.
And I think they're one of the few options that has a free Mongo server.
So if you want to just set up a little prototype and get started and play around, they have like a half a gig free server you can set up and use there.
And so that's pretty sweet.
They're great.
I use them.
I still use them today.
I use Atlas a little bit, but I use MLab as well.
One of the nice things about MLab is that there's an integration to Heroku as well.
So if you're using Heroku, you can get the MLab plan for free, and then it's just kind of like I'm not running a server anywhere.
Somebody else is doing it for me, and I can play around with things and have them work and with authentication enabled as well.
Yeah.
Yeah, those all come set up correctly, let's say.
Yes.
Perfect.
All right.
Awesome.
So, yeah, just right now I'm running my own MongoDB server on my own VM, but I've been working with Mongo for six years.
So I feel like that's probably a point at where I can go run my own VM and do my own backups daily, things like that.
But, yeah, these are all good options, and I know that jumping on one of the hosted ones is pretty nice to get started.
So let's talk about some other stuff that you've been up to.
First of all, like all of this MongoDB work, you now just came out with a MongoDB course for Python developers, right?
Yeah, so I'm working with Pact Publishing, and they wanted to put out some courses on MongoDB.
And I just came out with a video course called Developing with MongoDB and kind of a three-hour course that gives you an intro, both of what is MongoDB, how does it work, how is it different from relational databases,
takes you through using it with Python, takes you through some schema design.
It doesn't get into some of the big data analytics, you know, using it with Hadoop or some of the other things, but it does give you a good foundation in MongoDB.
And, you know, I was happy to say that that was just published yesterday, which would be the 25th of April.
We're recording on the 26th, so happy to see that out there.
Yeah.
How's that for timing?
Perfect, huh?
Yeah.
Nice.
That's cool.
That must have been fun to make.
And you also, speaking of ODMs, you wrote a book with the R instead of a D in there as well, the ORM, right?
I did.
This is prior to my involvement with MongoDB, and the name of the book is Essential SQLAlchemy.
It's also an O'Reilly title.
So SQLAlchemy, if you are using Python and you are using an SQL database and you are not using SQLAlchemy, then you're missing out, I would say.
And you're probably a Django developer because they have a really nice ORM themselves, and it has a lot of other features, if you're using Django, that are nice.
But SQLAlchemy is one of the best libraries, object-relational mappers.
I mean, it is the best I've ever seen.
Yeah, it's really, really good.
I've used it a lot, and it's been perfect.
Yeah.
A lot of the time when you get something like an object-relational mapper, then you give up a lot of the goodness of, like, a lot of the strengths of SQL.
And I think that Mike Baer, who is the author of SQLAlchemy, really did a good job of giving you the abstractions of an ORM while still allowing you to get the performance of raw SQL.
So I was really happy with that, and a second edition of that came out in the last year.
I didn't have a lot to do with the second edition, but because I wrote the first edition, I get to have my name on the cover.
Nice.
Perfect.
Yeah, and I actually had Mike Baer on one of the first episodes, episode five, so dug into that.
Yeah, I like SQLAlchemy a lot.
He is a smart dude.
Indeed.
All right, Rick.
So we're about out of time.
I don't want to take all your day up, but so let me ask you two quick questions before I let you out of here, and then one more thing after that.
So if you're going to write some Python code, what editor do you open up?
I open up Sublime Text 3.
Sublime Text.
All right.
Definitely a solid one.
Do you have extra plugins, or do you use the Anaconda IDE thing that plugs in there?
Not the Continuum thing, but something else.
No, I pretty much use almost the default install.
I mean, package control is in there.
Occasionally do some React programming to mention a different programming language, but get the JSX plugin and things like that.
But it's Sublime, pretty vanilla for me.
Nice.
There's a ton, over 100,000 packages on PyPI.
Is there one that's kind of notable you think maybe people haven't tried or heard of that you want to recommend?
Well, other than things like PyMongo and SQLAlchemy that we've already mentioned, one of the ones that it just comes up over and over, and people may have already, a lot of people have heard of it, is Requests.
It's the most un-Google-able package name.
But if you're going to do any web programming in Python as a client, you need the Requests library.
Yeah, absolutely.
So I think it would be un-Google-able if it weren't so popular.
Yeah, true.
So Python Requests is your best bet.
Yeah.
Exactly, exactly.
All right.
Well, that's about all the time we have to talk about Mongo for today.
Any final call to actions?
People are excited about this stuff.
How do they learn more, do more?
So MongoDB.org can teach you a lot about MongoDB.
You know, obviously the course, which will be in the show notes, but there's also MongoDB World coming up this summer in Chicago.
So that might be a good place if you're really interested in this database.
It's probably the cheapest education that you can get.
And it's, you know, two days of talks and tutorials before that.
So I guess those are my calls to action.
Yeah, cool.
MongoDB World, that's like the PyCon of MongoDB.
Yes.
That's the big one to go to.
It's in Chicago, and that's cool.
It used to be in New York City every time.
Yeah, this is the first time that they've kind of ventured out of Manhattan.
So it'll be interesting to see what goes on there.
Yeah, indeed.
All right.
Well, Rick, thank you so much for being on the show.
It's been great to chat about Mongo.
All right.
Well, thank you.
This has been another episode of Talk Python to Me.
Today's guest has been Rick Copeland.
And this episode has been sponsored by Advanced Digital and Hired.
Advanced Digital would love to work with you to build and extend one of the most visited websites in the U.S. in Python.
Reach out to them at python.advance.net to see if there's a fit.
Hired wants to help you find your next big thing.
Visit talkpython.fm/hired to get five or more offers with salary and equity presented right up front and a special listener signing bonus of $600.
Are you or your colleagues trying to learn Python?
Well, be sure to visit training.talkpython.fm.
We now have year-long course bundles and a couple of new classes released just this week.
Have a look around.
I'm sure you'll find a class you'll enjoy.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, Google Play feed at /play, and direct RSS feed at /rss on talkpython.fm.
Our theme music is Developers, Developers, Developers by Corey Smith, who goes by Smix.
Corey just recently started selling his tracks on iTunes, so I recommend you check it out at talkpython.fm/music.
You can browse his tracks he has for sale on iTunes and listen to the full-length version of the theme song.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Smix, let's get out of here.
Stating with my voice, there's no norm that I can feel within.
Haven't been sleeping.
I've been using lots of RSS.
I'll pass the mic back to who rocked his best.
First, developers, developers, developers, developers.
First, developers, developers, developers.
First, developers, developers.
First, developers.
you