Alex, we'll now talk about getting to know, look at first pioneers, PouchDB and CouchDB.
Let's welcome him.
All right, hello.
Hi, my name is Alex.
I'm from a company called Neighborhoodie in Berlin, and I'm going to show you PouchDB
and CouchDB.
It's just going to dive straight in and then do something very ill-advised,
namely demo the entire thing live, because I think to chose it very well.
So CouchDB is a non-relational document-based database.
It is extremely good at sinking data back and forth and doing all of the things that
track as generally interested in.
It's built in Erlang and it runs on the server.
PouchDB with a P is the JavaScript implementation of kind of the same thing
and it runs in the browser.
And together, they talk with each other and they're really good at building
sync engine based offline capable collaborative web apps with real-time
ish capabilities.
And yeah, because we think that the barrier to entry is very low and they're very
easy to reason about, we're just going to do the whole thing live right now.
Let's see if that works.
We're going to go to the PouchDB website because on the PouchDB website PouchDB itself is hosted there.
And so we're just going to do what I said.
We're going to get ourselves a PouchDB instance.
So doing things, this angle is very bad for me to see my cursor.
But I think we can make it work.
Okay, so I stupidly just scrolled past that.
But we just got ourselves a PouchDB instance.
It's basically a wrapper around indexDB.
Usually what people like to do with databases is put data in them.
So for this presentation, we're going to put variables into our database.
Everything in Couch and Pouch is JSON.
So keys and values.
Some keys are special.
They have an underscore.
This is predictably the unique ID.
We're only going to have one Badger.
So that's fine.
Put the Badger in.
Sweet.
Now the Badger.
Usually you want to get stuff out again.
There are many ways of getting stuff out of Couch and Pouch.
We're going to do the simplest one and use the get method on our database.
I promise this gets more complex and interesting in a minute.
You just get it by its ID.
Very straightforward.
There's a Badger.
Awesome.
And we can see there are three keys that we just put in.
Food type and ID, but there's a fourth key that we didn't put in.
So this is something PouchDB did for us.
This is a document revision.
So now all you need to know is the document revision has two parts.
In front of the dash is an incrementing integer that tells you the how many
If version of the Badger this is.
So this is the first thing after the dash is the content addressable hash of the document.
Which makes it very easy to compare documents and revisions with each other very cheaply.
We're going to see why that's cool later on.
Yeah.
So you kind of post add multiple animals.
We're going to do that really quickly.
So we have some more things to look at.
So this is a bulk dox thing.
You just put in an array of JSON.
Okay.
These are all.
So every write to Couch and Pouch is the topic.
And when you do multiple of them, they are still handled individually.
So if one of them fails, the others will work, which is nice.
And yeah, sometimes you want to know how many animals you have.
So let's look at the easiest way to get what is my cursor and why.
The easiest way to get data out of it.
And that's with the all dox command.
We pass in an option that says include the dox because we know how many there are.
We know that there are small sometimes you would not want to do this.
And then you get your animals.
Cool.
You can see they all have a rev.
Brilliant.
That covers reading and writing.
So you can also power your user interface with PatchDB.
So Patch and Pouch and Couch both have a thing called the changes feed,
which is basically just an event a meter that emits an event
whenever something changes.
And you can see how you could easily attach that.
If you have a reactive front and you are, for example,
you attach the changes handler to the state management of that
and then decide whether you want to update.
The view, we're just going to add one of those really quickly.
And this is also just a method on our database instance called changes.
We wanted to start now.
We say live is true, which means it will stay active until we turn it off again.
And again, we would like the entire document body inside the change.
Just going to start that.
And to actually trigger this, we now have to do something with the database.
So we haven't done updates yet.
So let's do those next.
You might assume updates work a bit like this.
Oh, I forgot to copy the thing on second.
Work a bit like this where you just do a put again.
You reuse an idea that you know exists and you put in some new keys and values.
And you would be wrong because that doesn't work.
Why does it not work?
So you get a big error message, which is interesting for two reasons.
First of all, there's an HTTP status code in there.
409 conflict, which is curious because we didn't make any network requests.
So why is that there?
CouchDB, like the big one, is an HTTP server.
Every piece of data, every action you can take on the data,
every function of the database has an HTTP endpoint.
And since patchDB is an implementation of couch, it only makes sense that it behaves consistently.
In addition, patch can also be used as a client library for couchDB.
So it just makes sense to do it this way.
The more interesting questions, why is there a conflict?
So couchDB has a concept of history with its document revisions.
So when you make an update, you not only have to specify which ID you want to update,
you also have to specify which state of that document you want to update.
And that's basically what underpins the very awesome
syncing capability of couch and patch.
So if you recall, we already had our badge on.
And our badge already had an idea.
So the easiest way to do this is to just reuse the badge on.
We're going to destructure the poor guy and just override the one key that we want to change.
And that works.
And you can see, first of all, the changes feed fired.
So we could now, if we had a UI, we could now take this change, see if we need to do anything with it.
And update the state.
And you can also see that the document now is at revision two.
And the hash is also changed because the document is changed.
All right.
Now let's sync some data.
We're going to connect the patch DB, which runs in the browser to a remote couch DB,
which is running on this laptop, but you know what I mean.
It could be anywhere.
So couch and patch support true multi-primary replication, meaning you can connect several databases,
and several, I mean, many more than two via replication,
and they'll eventually be consistent with each other.
You can also do partial replication, filter replication as you like.
And the big selling point here is, of course, that these networks can be partitioned.
So the database is still fully functional, and they will sort themselves out once they reconnect.
So let's start a replication.
Real quick.
This replication goes from the local database to a remote one, and back again, it is live.
So again, it stays open until we close it, and it will retry if it goes offline,
which is kind of the secret superpower here.
All right.
First thing that's going to happen is a pile of errors are going to happen.
Why is this?
Because again, couch DB is an HTTP server.
If patch wants to know something about resource that isn't there, it will get a full or full.
That's totally normal, which is why patch DB repeatedly tells us that this is totally normal.
I'm going to hide those.
And now we can also see that the replication has done something.
It's going to push, what does it push?
It is pushed out for documents into the database.
So let's look at those.
This is photon.
This is the admin panel that couch just hosts for you.
And we're already in the correct database.
And if I refresh, we can see.
Let me hit that bigger.
We have a document.
The badger is that revision two.
And we're going to do a change.
So we're going to make the ferret a bit nicer.
I have it.
It can be instead of blood.
I don't know what ferret see.
I'm sorry.
And if you go back to here, you can see that there was a pull.
That's our ferret being pulled.
And the changes feed is also fired with our updated ferret.
And this is nice because we've just specified the changes feed in our browser.
But that change came from somewhere completely different.
And we don't care.
We have one changes feed handler.
It could be our own change on this client could be somewhere else.
All the same thing.
Cool.
Now let's stress this a bit and make a thousand animals.
And we're going to put them directly into the couch.
And with this, I just want to demo that.
Pouchy B can also be a client for a note.
Couchy B.
Oops.
Oh, I just noticed that.
One second, I missed a place to file.
That was dumb.
Oh, no.
I can't find my thousand animals anymore.
That was very unfortunate.
There we go.
There are a thousand animals.
Please don't pay huge arrays of Jason at home.
Point.
And the changes feed fires a bunch of times.
And if we go here and refresh, we can see everything's full of bears.
And that would usually be a problem, but in this case it's what we want.
If we go back here and we check with all docs again how many animals we have,
we will see that they have already been replicated back down into the Pouchy B.
And we have a thousand for animals.
So that's very cool.
Okay.
I have to rush a bit.
Let's go offline and do the really exciting stuff.
Where's my offline button?
We're taking this browser offline.
And we're just going to do some things.
If we weren't offline, for example, we're going to add a new animal.
Because a thousand for animals is nowhere near enough.
We're going to add an auto.
That just works really in.
Let's delete the pangolin on account of it not being furry enough.
So, deletes in cartoon culture.
Interesting.
It's something in a distributed database.
Because once the other databases reconnect,
they will just replicate that thing back into existence.
So you have to keep track of the deletion and the way we do that,
we just market as deleted with a special key.
Deleted true.
And now the pangolin is gone.
And yeah, the changes feed also explicitly tells us that it's a deletion,
which is also quite useful.
But all this really means is that we can really easily build apps
that seamlessly work online or offline without the end user.
Or even us as developers having to care particularly much about the connectivity status.
As long as our code does not talk to the network,
the replication protocol would just do the thing in the background.
Right.
Now, conflicts.
Let's close conflicts.
We're going to do some conflicting offline rights.
Let's see what happens there.
We're going to get a badger.
And we're going to let the badger in the browser
be a ramen noodle efficient order.
And we're going to let the badger in the server.
Remember, these are no longer connected.
Yeah, I'm hurrying.
Yeah, but I'm pretty much on track.
It's all good.
Talking with safe successfully.
Cool.
We have two parallel badgers.
There are now two versions of the same badger,
which is the real one.
Only time will tell.
For now, this is shooting as badger.
They both exist.
So let's reconnect and see what happens.
So the first thing that's going to happen is probably, hello.
Yeah.
So one part of the replication has happened.
So it's pulled to the change from the server.
And in a second, it's also going to do a push.
There's an incremental back off thing happening here,
so it doesn't club up the connection.
Take a few seconds when you leave there.
Come on.
There we go.
Okay, now let's see which badger is real badger.
And then we are near the end of the tour.
So what happened?
The badger has won.
Cool.
Does that mean the ramen badger is now a conscient history?
No.
The ramen badger lives on.
He lives behind the conflict button.
So it can actually be in part should be do not do last right wins.
Because in some use cases,
that is equivalent to just randomly deleting user data,
which sometimes you cannot do.
So we give you as a developer the option of choosing what to do with your conflicts.
You can ignore them, which is effectively last right or wins,
or just random right or wins, because we have no blocks.
Or you can do proper conflict resolution,
which may even mean asking the users what they originally meant.
Okay.
That.
Yeah.
So with many other offline first solutions,
quite a lot of your work will be just getting to this point, right?
You have to add a lot of abstractions between your sync layer and your actual data.
And because a lot of other systems can't handle arbitrary data,
you'll see we don't have a schema, we didn't define anything, right?
With cash and pouch, the conflict handling does not care what your data looks like.
And it's always just human readable Jason.
So it's offline capable, real timey, it sinks, it's conflict aware,
and we did all of that without writing a single line of code.
We only invoked some library methods.
All right. So just do a small recap about cash and pouch.
So the open source Apache Foundation projects with a long history,
nobody's going to sell you anything.
Built on open standards, no lock-in, HTTP and Jason,
if your stack speaks that you're dumb, basically.
True multi-primary replication, human readable state always,
in flight and transport, not operations or transactions being stored,
conflict aware, through and through completely indifferent to your data structure.
No auto resolution magic, you get to decide what to do,
plus loads of other awesome features.
Yeah, we love cash to be in pouch.
We've done a lot of interesting work in the past 10 years all over the world.
Please come talk to me and Jan, the man over there about this.
We enjoy this topic a lot as you may be able to tell.
We're quite friendly and we also have stickers, and that's it.
Those are the URLs. Thank you very much.
Thank you.
You have the tools to remain as far as possible.
I can't see anything, but we have some.
Yes.
There was a second where you had edited in the admin dashboard,
and you went back to the application, or just the console,
and you saw that it was changed.
Yeah.
Why was that was it pulling for this like the changes feed?
It's actually two separate things.
So the replicator we had set up a bi-directional replication.
So any change on the couch to be what automatically
you get pulled replicated into the pouch.
And then the changes feed fired because something changed in the local database.
I see.
So it's like being changed from the same place, basically.
Yeah, in a way. Yeah.
Yeah.
Doesn't really care where the change came from in the head.
Nice.
Some other question.
Is it mainly a key value store, or is there any like transaction
multi-document functionality?
You can build one on top if you like.
It just stores JSON.
I mean, it also stores binary data if you wanted to.
But in principle, it's just JSON.
But we've built a transactional store on top of that as well.
It's entirely possible.
Like a ledger system.
Yeah.
Thank you.
I didn't catch this.
If you don't as the developer resolve the conflicts,
or the multiple clients guarantee to converge on a consistent state.
Yes.
It's always a deterministic even if the separator from each other.
Okay.
Good question.
Yes. Absolutely. Good question.
More or good.
Okay.
Alex, thank you very much.
Thank you.