<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Trey Botard</title>
    <description>The latest articles on Forem by Trey Botard (@treybotard).</description>
    <link>https://forem.com/treybotard</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F334122%2Fb9f7e2db-060a-472d-9b74-797d332bd05a.jpg</url>
      <title>Forem: Trey Botard</title>
      <link>https://forem.com/treybotard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/treybotard"/>
    <language>en</language>
    <item>
      <title>Fluree is moving to Discord</title>
      <dc:creator>Trey Botard</dc:creator>
      <pubDate>Tue, 04 Jan 2022 01:06:44 +0000</pubDate>
      <link>https://forem.com/fluree/fluree-is-moving-to-discord-3pdh</link>
      <guid>https://forem.com/fluree/fluree-is-moving-to-discord-3pdh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The Fluree community has seen substantial growth over the last year.&lt;br&gt;
With the velocity of growth and the big goals we have for the community,&lt;br&gt;
we need a new home.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Discord has become an ever-present tool for communication on the web. The Fluree community has been on Slack for the past several years and for the most part we have been satisfied by the platform. However, over the past year, we've seen significant growth and as we've grown, we've begun to run up against some of the shortcomings of Slack as a platform for an open community. As we imagined where we want to take the Fluree community going forward, it became harder and harder to see how we could modify our vision to fit within the bounds of Slack. We needed a new platform for our community. After investigating the alternatives, we found Discord to be an extremely attractive option with all of the benefits provided by Slack and a ton of new functionality to boot. We did some preliminary internal testing, then tested the waters with a couple weeks of beta testing (shout out to our Beta testers!) and found the experience to be even better than we had hoped.&lt;/p&gt;

&lt;p&gt;So, we made the exciting decision to migrate our community on over.&lt;/p&gt;



&lt;h2&gt;
  
  
  Why Migrate?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  No message limits
&lt;/h3&gt;

&lt;p&gt;The primary limitation in Slack is the message limits. If you weren't aware, Slack only allows up to 10,000 messages per workspace. There are over 700 members in the public Fluree Slack and the amount of chat happening meant that we were only able to see messages within about a 6-month window. As our community grows, that window will only shrink and the knowledge shared within this space will be lost at an accelerated pace. Discord has no message limit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Voice chat and screen share
&lt;/h3&gt;

&lt;p&gt;Another big point of differentiation between the two platforms is the availability of voice chat and screen sharing. Discord has a ton of features around this which we will begin to take full advantage of. We want to enable our members to self-organize and work on things together using the Fluree Discord as needed. This will enable just that. Not to mention the functionality the Fluree team can use to host events and activities from with Discord. (We have some fun stuff planned for this year!)&lt;/p&gt;

&lt;h3&gt;
  
  
  Open by default
&lt;/h3&gt;

&lt;p&gt;Another issue with Slack for an open community is the way channels are structured. Channels are hidden by default and require a member to be invited or actively search for new channels to join. This is not the way Discord is set up. All channels are public by default, which creates an easy path to exploration and cross-pollination, with good tooling for a user to manage notifications per channel or category as desired. We think this is better for an open community and are excited for this change in structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better moderation tooling
&lt;/h3&gt;

&lt;p&gt;Fortunately, this hasn't been an issue thus far, but moderation is a &lt;em&gt;vital&lt;/em&gt; part of community management. Creating a safe space for all of our community members is extremely important to the Fluree team and frankly the tooling for moderation in Slack is practically non-existent. Discord provides functionality which will enable us to create the spaces we want and ensure a welcoming, helpful, and safe environment for all who choose to join us.&lt;/p&gt;



&lt;h2&gt;
  
  
  Timeline
&lt;/h2&gt;

&lt;p&gt;Here's the plan for the migration: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Thurs. Jan 6th&lt;/em&gt;: Open Discord server to the public.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Mon. Jan 10th&lt;/em&gt;, and &lt;em&gt;Fri. Jan 14&lt;/em&gt;: Fluree DevRel team will be available for questions in the Discord to assist with the new tool.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Mon. Jan. 31st&lt;/em&gt;: Close public Slack channels to new comments. Begin migrating private channels to shared channels where needed. 

&lt;ul&gt;
&lt;li&gt;We will migrate private support channels to shared Slack channels from our internal Slack workspace. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Thurs. Feb 3rd&lt;/em&gt;: February Office Hours to be held in the new Discord server!!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, the team will be available for any questions in both Discord and Slack for the duration of the migration and are more than happy to assist where needed. &lt;/p&gt;




&lt;p&gt;We are extremely excited for this new chapter of the Fluree community. There will be bumps in the road as we migrate such a large community, but we are confident this is the right choice, both for the long term health of the Fluree community and for Fluree itself.&lt;br&gt;
Keep an eye on our &lt;a href="https://twitter.com/flureepbc"&gt;Twitter&lt;/a&gt; in the coming weeks for an invite link to the new Discord server. If you're in the Fluree Slack, we'll&lt;br&gt;
be making an announcement there as well.&lt;/p&gt;

&lt;p&gt;We look forward to seeing you in the new Fluree Discord!&lt;/p&gt;

</description>
      <category>fluree</category>
      <category>discord</category>
      <category>community</category>
    </item>
    <item>
      <title>Fluree in Docker - A Single Instance</title>
      <dc:creator>Trey Botard</dc:creator>
      <pubDate>Thu, 07 Oct 2021 21:25:12 +0000</pubDate>
      <link>https://forem.com/fluree/fluree-in-docker-a-single-instance-15i8</link>
      <guid>https://forem.com/fluree/fluree-in-docker-a-single-instance-15i8</guid>
      <description>&lt;p&gt;Managing dependencies is a pain in the tuchus. Whether in the cloud, in a private data center, or just on your laptop, ensuring that you have the correct version of Java or Node or whatever other runtime works properly with both the application and the OS and all of the other dependencies can quickly turn into a nightmare. Docker solves this by bundling all of the dependencies together in a single image such that as long as the Docker runtime is deployed on the target infra, your app should function as desired. No muss, no fuss. 🥳&lt;/p&gt;

&lt;p&gt;Let's walk through the set up necessary to get your Fluree backend up and running. (Deployment to a public cloud will be out of scope for this post). This will be the first of a 3 part series on working with Fluree in Docker. The next one will be about setting up a Transactor Group!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;To begin with, you will need to have Docker on your machine. Please visit the &lt;a href="https://www.docker.com/get-started"&gt;Docker Getting Started Docs&lt;/a&gt; to get it set up, if you don't have it configured already.&lt;br&gt;
Once Docker is installed and running you will need to grab the &lt;a href="https://hub.docker.com/r/fluree/ledger"&gt;Fluree ledger image&lt;/a&gt; from DockerHub. The &lt;a href="https://docs.docker.com/engine/reference/run/"&gt;Docker CLI&lt;/a&gt; is a great tool for managing images on your machine. We will use the &lt;code&gt;docker pull&lt;/code&gt; command to grab the fluree/ledger image. Open a terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;docker pull fluree/ledger:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of writing, this will pull the 1.0.0 beta 15 ledger image from Docker Hub, which is the most up-to-date version of Fluree. Once the Fluree ledger 1.0.0 is released, beta releases will go under their own tag. At any time, you can pull a specific release, if that is needed. You would simply define the image to pull using the tag like this: &lt;code&gt;fluree/ledger:1.0.0-beta14&lt;/code&gt;.&lt;br&gt;
You can see all of the release tags for Fluree in our &lt;a href="https://github.com/fluree/ledger/tags"&gt;Github Repo&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Set up and run the container
&lt;/h2&gt;

&lt;p&gt;Ok, you have the image, now what?&lt;br&gt;
There are a couple of parameters which Fluree needs in order to start up correctly.&lt;br&gt;
These can be passed in when starting the container using the &lt;code&gt;docker run&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;You can simply start the image by calling &lt;code&gt;docker run fluree/ledger&lt;/code&gt;, but this will not expose the ports you will need to have in order to use the HTTP endpoints. Internally, Fluree listens on port 8090 for the HTTP calls, so this port will need to be mapped to an exposed, public port on the container. This can be done with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker run -p 8090:8090 fluree/ledger
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ports correspond to ExternalPort:InternalPort. So, if you have 2 containers running, you will need to map the first of the two to a different port and leave the second number as-is because that is the port which Fluree is listening on. So for your second container, you would pass &lt;code&gt;-p 8091:8090&lt;/code&gt; or some other port number of your choosing.&lt;br&gt;
This spins up Fluree inside of your container, you will see the default configs print to the terminal and some messages about the consensus and state of the server. You can see the container and some metadata by running &lt;code&gt;docker ps&lt;/code&gt; in another terminal.&lt;/p&gt;
&lt;h3&gt;
  
  
  Naming your Container
&lt;/h3&gt;

&lt;p&gt;By default, Docker will assign your container both a CONTAINER_ID and a NAME, which you can see via the &lt;code&gt;docker ps&lt;/code&gt; command or in the Docker Desktop UI. The name will be 2 randomly assigned words, but you can name your container when you initialize it with the &lt;code&gt;docker run&lt;/code&gt; command. This is useful because you can then use that name to restart your container, if you stop it for whatever reason. (At this point stopping the container will lose any data, but in a bit, we will connect the container's file system to a local directoy for data persistence 🙌). You can do this by adding the &lt;code&gt;--name&lt;/code&gt; flag to the &lt;code&gt;run&lt;/code&gt; command, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker run -p 8090:8090 --name ledger1 fluree/ledger
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when you run &lt;code&gt;docker ps&lt;/code&gt;, the NAMES field will be &lt;code&gt;ledger1&lt;/code&gt; instead of a randomized pair of words.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One caveat to using the &lt;code&gt;--name&lt;/code&gt; flag is that if you stop your container or kill the terminal, that name will still be associated with that container. So you may need to run &lt;code&gt;docker rm ledger1&lt;/code&gt; to remove the container, if you want to &lt;code&gt;docker run&lt;/code&gt; with the name ledger1 again. (This applies to the randomly-assigned container names as well. They will exist on the machine until they are removed.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Interacting with your Instance
&lt;/h2&gt;

&lt;p&gt;Now that your ledger is up and running on your machine, there are a few ways for you to interact with the ledger.&lt;/p&gt;

&lt;h3&gt;
  
  
  Admin UI
&lt;/h3&gt;

&lt;p&gt;Every instance of Fluree contains a small utility for working with the ledgers, called the AdminUI. This is a browser based UI maintained by the Fluree team for working with instances of Fluree, whether as a single instance or in a transactor group. Once you have your Fluree instance ready with the HTTP port exposed, you can start the Admin UI by going to &lt;code&gt;http://localhost:[EXPOSED PORT]&lt;/code&gt; in your browser.&lt;br&gt;
If you used the command above to start up your instance, use 8090 for the &lt;code&gt;[EXPOSED PORT]&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We have a &lt;a href="https://youtube.com/c/fluree"&gt;YouTube&lt;/a&gt; video walkthrough of the AdminUI coming soon.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  HTTP Calls
&lt;/h3&gt;

&lt;p&gt;Fluree also contains an HTTP client which exposes several &lt;a href="https://docs.flur.ee/api/1.0.0/downloaded-endpoints/downloaded-examples"&gt;HTTP endpoints&lt;/a&gt; for programmatically working with Fluree. Any of these endpoints can be hit by calling &lt;a href="http://localhost:8090/fdb/%5Bendpoint%5D"&gt;http://localhost:8090/fdb/[endpoint]&lt;/a&gt; or if the endpoint is ledger specific &lt;a href="http://localhost:8090/fdb/%5Bnetwork%5D/%5Bdb%5D%5Bendpoint%5D"&gt;http://localhost:8090/fdb/[network]/[db][endpoint]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At startup, there are no dbs on your instance, so it is recommended to start by using the &lt;a href="https://docs.flur.ee/api/1.0.0/downloaded-endpoints/downloaded-examples#new-db"&gt;/new-db&lt;/a&gt; endpoint first.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create a Persistent Volume
&lt;/h2&gt;

&lt;p&gt;Fluree is a ledger and database. Both of these things require persisting data, which Docker does by default, but we'll want to configure it ourselves. To do that, we will need to do what is called mounting a volume to the container. This volume will live on after the container is spun down or goes offline for some reason in the place where we told it to be.&lt;/p&gt;

&lt;p&gt;Fluree already has a mechanism for writing to a file system. In fact, there is a customizable parameter which enables you to specify the path in the file system where you would like Fluree to write its data. You can see all of the &lt;a href="https://docs.flur.ee/docs/1.0.0/getting-started/fluree-anywhere#config-options"&gt;configuration options&lt;/a&gt; in the docs. The config we are interested in now is &lt;code&gt;fdb-storage-file-directory&lt;/code&gt;. By default, this is set to &lt;code&gt;/var/lib/fluree&lt;/code&gt; whether Fluree is being run in a container or in a JVM directly on a server. This means we can use some functionality in the Docker CLI to bind a directory in our local filesystem to this directory &lt;em&gt;inside&lt;/em&gt; the container. Docker run has a flag called --volume (aliased to -v) where you can specify the two directories to be bound together. It will look like this &lt;code&gt;-v "[local/path/to/dir]:[container/path/to/dir]"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For my example, I will tell my container to bind to &lt;code&gt;Users/treybotard/Projects/fluree-data/docker-blog/&lt;/code&gt;. To put this together with the &lt;code&gt;run&lt;/code&gt; command from above; your command should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker run -p 8090:8090 -v "/Users/treybotard/Projects/fluree-data/docker-blog/:/var/lib/fluree" fluree/ledger
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that I've run this command, I can open up the AdminUI, add a new ledger to my Fluree instance, and when I path to my docker-blog folder, I will see 2 folders, &lt;code&gt;group/&lt;/code&gt; and &lt;code&gt;ledger/&lt;/code&gt;. These are the folders Fluree uses to maintain raft logs (in &lt;code&gt;group/&lt;/code&gt;) and the encrypted indexes (in &lt;code&gt;ledger/&lt;/code&gt;). I'm not going to go into too much detail here about this structure. If you are interested in reading more about how Fluree maintains the &lt;a href="https://docs.flur.ee/guides/1.0.0/architecture/indexes"&gt;indexes&lt;/a&gt; or how Fluree interacts with the &lt;a href="https://docs.flur.ee/guides/1.0.0/infrastructure/file-system"&gt;file system&lt;/a&gt; you can read more in the docs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Private key file
&lt;/h3&gt;

&lt;p&gt;When using the &lt;code&gt;--volume&lt;/code&gt; command to persist your data outside of the container, if a private key is not provided on start-up, Fluree will create a default private key. This key (whether provided or generated at startup) is used for a few access controls in developement mode. What this means is that if you want to reuse the same identity to access the persisted data, you will need to store your key outside of the container and pass it in when spinning up a fresh container. This can be done a few different ways, but for simplicity's sake, we'll just look at passing the private key into the container as an environment variable with &lt;code&gt;-e&lt;/code&gt;. Using an environment variable requires passing in &lt;code&gt;-e FDB_GROUP_PRIVATE_KEY=[PRIVATE_KEY]&lt;/code&gt; when starting the container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now our command looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker run -p 8090:8090 -v "/Users/treybotard/Projects/fluree-data/Docker-blog/:/var/lib/fluree" --name ledger1 -e FDB_GROUP_PRIVATE_KEY=123456789 fluree/ledger:latest
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker start and stop
&lt;/h2&gt;

&lt;p&gt;One very convenient way to maintain my development environment is to use the &lt;code&gt;--name&lt;/code&gt; flag on a container with a volume mounted on it. What this enables is the &lt;code&gt;stop&lt;/code&gt; and &lt;code&gt;start&lt;/code&gt; functionality in the Docker CLI. If i have a container specifically for a client project or a demo I am working on, I give it a meaningful name "docker-blog" and mount it to a volume stored next to the source code where I am working. I can then conveniently run &lt;code&gt;docker start docker-blog&lt;/code&gt; when I am ready to work on the container. It knows which ports to use and can spin up the container exactly the way it was when I ran &lt;code&gt;docker stop docker-blog&lt;/code&gt; when I stopped working on it before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Convenience Commands and Flags
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;--rm&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you are just testing out some some ledgers and are making some throw-away ledgers, I recommend adding the &lt;code&gt;--rm&lt;/code&gt; flag. Going to spin up a named container which you forgot to spin down, but getting an error that the container name already exists gets old quickly. This will remove the container when you either CTRL+C or send SIGINT to the container some other way.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;-d&lt;/code&gt; and &lt;code&gt;attach&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you have been spun up a Fluree container before, you will have seen that the output is relatively chatty. One easy way to not have to see that in your terminal is to pass the &lt;code&gt;-d&lt;/code&gt; flag when starting up the container. This will run Fluree in a detached process and not print to the console. You can run &lt;code&gt;docker attach [container name]&lt;/code&gt; to reattach to the console and see the logs in your terminal. If you didn't give the container a name, you can look it up with &lt;code&gt;docker ps -a&lt;/code&gt; to see all the containers, including the ones which are stopped.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;docker exec&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes, it can be very useful to have a bash terminal inside a running container &lt;em&gt;while Fluree is running&lt;/em&gt;. You can use the &lt;code&gt;docker exec&lt;/code&gt; command to run a command inside a running container. One useful way which I use this is to run &lt;code&gt;docker exec -it [container name] /bin/bash&lt;/code&gt;. This opens a bash terminal in the working directory of my container where Fluree is running.&lt;/p&gt;

&lt;p&gt;It can also be useful to access the file system in a container with Fluree inside it, even when Fluree is not running. To startup a container without initializing Fluree, you need to use &lt;code&gt;docker run&lt;/code&gt;, but override the &lt;code&gt;--entrypoint&lt;/code&gt;. That looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker run -it --entrypoint=bash fluree/ledger
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start up a container and give you a bash terminal with which to explore.&lt;/p&gt;

&lt;p&gt;With these commands, a large percentage of the functionality needed to work with Fluree locally can be achieved. Next week, we'll take a look at how to set up a Transactor Group (several Fluree instances networked together) in Docker using similar commands &lt;em&gt;and&lt;/em&gt; Docker compose!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>fluree</category>
      <category>blockchain</category>
      <category>database</category>
    </item>
    <item>
      <title>Time traveling with Fluree</title>
      <dc:creator>Trey Botard</dc:creator>
      <pubDate>Thu, 01 Jul 2021 18:18:35 +0000</pubDate>
      <link>https://forem.com/fluree/time-traveling-with-fluree-30nj</link>
      <guid>https://forem.com/fluree/time-traveling-with-fluree-30nj</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7f1ejj4frbx4h3u13ifo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7f1ejj4frbx4h3u13ifo.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;When you get down to it, if you are building an app with Fluree as the backend, it is simplest to think of Fluree as a database. This can be a useful way to think about working with Fluree, but by doing so there is a lot being left on the table. The unique combination of technologies which make Fluree what it is enable some extremely powerful functionality and unlock ways of working with data which are either uncommon or simply not possible with other data stores. Let's talk about what some of those are, how to use them, and what this type of functionality could enable in your Fluree-backed application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;In addition to a graph database for querying data, Fluree is built with an immutable ledger as the backbone which holds the dataset. This part of Fluree is what enables some really interesting and particularly unique functionality. 'Immutable ledger' is one of those terms which I had to Google in order to understand when I started at Fluree, so let's break that down a bit.&lt;/p&gt;

&lt;p&gt;Fluree associates related data elements, called subjects. Each subject has an &lt;code&gt;_id&lt;/code&gt; which is used to correlate the attributes (called predicates) and the values of those predicates together to form the "facts" about that subject. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fluree is based on an extended version of the W3C standard for RDF, which is where this notion of SPO (Subject, Predicate, Object) comes from.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can think of it like a row in a db table with &lt;code&gt;_id&lt;/code&gt; being the unique identifier for the row, predicates are the columns, and the values are the fields. Each field makes up a fact about the instance of data stored in that particular row in the db. For example, in a Dog table with a Breed column, each row corresponds to a unique Dog who is described by the attributes and fields. The same idea holds in Fluree. An &lt;code&gt;_id&lt;/code&gt; groups the related predicates, which point to values, in order to make up the "facts" of that subject. So, the &lt;code&gt;dog/breed&lt;/code&gt; predicate would point at an object, &lt;code&gt;"french bulldog"&lt;/code&gt;, for example. At the point in time when that fact was written to the ledger, that specific subject's breed was french bulldog.&lt;/p&gt;

&lt;p&gt;Each of these facts are stored in an immutable data structure. Immutable means that those data structures are not available to be modified or changed in any way. Instead of simply changing a value or updating a "row" in the data, Fluree will make a new true fact in the ledger and associate it with the appropriate subject. If this is a value which is being "modified" then Fluree will make two new facts; one where the old fact is false and the second a new, true fact, both of these facts are then associated with the subject and written to the ledger. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is part of the "extension" to RDF. Each flake contains a boolean which indicates whether it is true or has been falsified. You can read more about this in the &lt;a href="https://docs.flur.ee/guides/1.0.0/architecture/flakes#flakes-as-flurees-foundation" rel="noopener noreferrer"&gt;flakes page&lt;/a&gt; in the docs. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This brings us to what a ledger is. You can think of a ledger as discrete units or "blocks" which contain the history of the data as it is transacted. These blocks are made of groups of immutable facts which are sent to an instance of Fluree. Each block is linked to the one which came before it so there is a chain of blocks from when the ledger was created to the current block. In Fluree, this chain is queryable, which means once some data has been transacted to Fluree you have the history of every data element in that data set! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvza8gu4gaxg4yqjqgzv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvza8gu4gaxg4yqjqgzv.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time travel
&lt;/h2&gt;

&lt;p&gt;So, back to those powerful pieces of functionality I mentioned at the beginning. &lt;br&gt;
There are two ways of querying the data which enable what we call time travel in the Fluree world. There are &lt;strong&gt;block&lt;/strong&gt; queries and &lt;strong&gt;history&lt;/strong&gt; queries, both unlock elements of Fluree which are only possible because of the immutable data structures and the ledger. Block queries enable querying the data state at specific moments in time and history queries allow you to get an overview of all of the modifications to a particular subject. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4j7xii41jbe9eftjdxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4j7xii41jbe9eftjdxz.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;We'll get into how each of these types of queries work, but first, why does this even matter? &lt;br&gt;
One of the primary benefits to having this type of view into your data is the ability to correlate events with the data state at the time that event happened. For example, say you are tracking prices for flights and you want to see what effect the weather had on flight prices or which day of the week prices tended to be the cheapest. The sky's the limit for these types of analytical queries. &lt;br&gt;
You also may want to enable your users to see the state of some piece of data when it was updated. I saw a comment on a LinkedIn post once and was pretty sure that the commenter worked for the company who's post he was commenting on, but his current job title was recently updated so I couldn't tell where he worked when the comment was added, only where he currently worked - the current state of the data. &lt;br&gt;
This type of functionality can be useful in a wide range of circumstances or situations. Having a way to view not only the current state of the data (table stakes for any database), but a way to see the state of a piece of data at a specified time OR for a specified range of time, can be extremely useful. Fluree goes a step further though. When you are querying some data a point in time, you are also seeing all of the facts which were true at that time as well. This includes all of the relationships which existed at the time. This is something which is not possible in any other database or data store that I am aware of. You are able to query not only the historical values of something in your data but also all of the context associated with that data as well. &lt;strong&gt;That is huge&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Now, think about how you would go about making something like this in your db of choice. Building out a historical view of a table in a traditional database, whether in a relational or NoSQL db, is a large and expensive maintenance burden, the size of your db will explode because of data duplication without significant optimization, and querying these db tables or documents can become relatively complex; specifically what happens to references? Does the reference point to the current table or is there a way to manage the reference such that it points to the correct row in the historical table? What happens when you want to do a join to with another table? There isn't an expedient or simple way to do either of those things, to my knowledge. One or two other data stores enable historical views, but are not able to pull in all of the context and maintain relationships as well. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8ldfla5sl21ij0ewhvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8ldfla5sl21ij0ewhvu.png" alt="Lying_down_working"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;Both of these operations are exposed via an API within a Fluree db instance. Simply passing a JSON to the &lt;code&gt;/block&lt;/code&gt; or &lt;code&gt;/history&lt;/code&gt; endpoint is all that is needed to query this type of data. Let's get into how to use each of these queries. I will be using the Fluree Query Language (FlureeQL), which is a JSON-based way to query the backend. Fluree also supports querying via GraphQL, SPARQL, SQL or calling these endpoints directly from Clojure, but we'll use FlureeQL to illustrate this functionality. If you want to read more about our query surfaces, check out the &lt;a href="https://docs.flur.ee/docs/1.0.0/query/overview" rel="noopener noreferrer"&gt;query pages&lt;/a&gt; for more details. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8bamzn25oik6lsg95v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8bamzn25oik6lsg95v.png" alt="Blocks"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  Block Queries
&lt;/h3&gt;

&lt;p&gt;There are two ways to query a block in Fluree. You can either issue a query against the &lt;code&gt;/block&lt;/code&gt; endpoint which returns the flakes in that particular block or range of blocks, or you can add a &lt;code&gt;"block"&lt;/code&gt; key to a basic query issued to the &lt;code&gt;/query&lt;/code&gt; endpoint. This basic query method of querying can, and probably will, pull in facts which were transacted to the ledger before the specified block. When you issue a regular query with a block key, you are issuing a query as if the specified block were the current block. &lt;br&gt;
Each of these types of query is beneficial, and can be useful depending on how you need to view your data. &lt;/p&gt;

&lt;p&gt;Let's start with a query issued to the &lt;code&gt;/block&lt;/code&gt; endpoint. This type of query currently supports 2 keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;number,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prettyPrint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;"prettyPrint"&lt;/code&gt; is a boolean, which if true, prints the results in a pretty printed, aka styled format, for easier reading, as well as separating the asserted and retracted flakes into their own arrays in order to make them easier to parse. The &lt;code&gt;"block"&lt;/code&gt; key is much more interesting. It can take a number, a string in the form of an ISO-8601 formatted date-time or duration, or an array which specifies a range of block for the query. &lt;/p&gt;

&lt;p&gt;For example, to query a specific block:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can query via a time stamp. This will return the first block which was transacted before this timestamp. In other words, it will give you the facts which were true at that time.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2017-11-14T20:59:36.097Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can also use an &lt;a href="https://en.wikipedia.org/wiki/ISO_8601#Durations" rel="noopener noreferrer"&gt;ISO-8601 formatted duration&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PT5M"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will return the state of the data as of 5 minutes ago. &lt;/p&gt;

&lt;p&gt;If you would like to query a range of blocks, you can pass an array containing the blocks you would like to see. This range is inclusive, meaning the data returned will &lt;em&gt;include&lt;/em&gt; both blocks you put in the array.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can also pass an array with a single block which will specify a lower, also inclusive, block and return the facts from that block up to the current block. &lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;/block&lt;/code&gt; endpoint will return an array of &lt;a href="https://docs.flur.ee/guides/1.0.0/architecture/flakes#flakes-as-flurees-foundation" rel="noopener noreferrer"&gt;flakes&lt;/a&gt;, each of which is a fact stored in Fluree at that block or range of blocks. While this is useful, it is probably more realistic that you would want to see a specific set of data using a normal query, but have the results returned as if they had been issued at some point in the past. This is also enabled in Fluree by issuing a query to the &lt;code&gt;/query&lt;/code&gt; endpoint which contains the &lt;code&gt;"block"&lt;/code&gt; key-value pair. This key expects the value to be structured in the same way as the examples above, with the value being one of a number, a formatted string, or an array of block numbers. So the main difference is that this type of query will pull in data which is not limited to a specific block, it returns data as if the query had been issued when that block was the current block. For example, if you had a Dog collection of subjects in your ledger, you could issue this query to see all of the dogs which had been transacted and not deleted as of block 7:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"select"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To read more on querying blocks, check out the docs pages for &lt;a href="https://docs.flur.ee/docs/1.0.0/query/block-query" rel="noopener noreferrer"&gt;block queries&lt;/a&gt; and &lt;a href="https://docs.flur.ee/docs/1.0.0/query/overview#block-key" rel="noopener noreferrer"&gt;querying with the block key&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5c4o4hf2n0mia8hdogtr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5c4o4hf2n0mia8hdogtr.png" alt="Brain Graphic"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  History Queries
&lt;/h3&gt;

&lt;p&gt;The way a &lt;code&gt;/history&lt;/code&gt; query is structured and issued is relatively similar to &lt;code&gt;/block&lt;/code&gt; queries, but are fairly different in what results are returned. As I mentioned above, a history query returns all of the modifications to a subject. I like to think of a block query showing the breadth of the data at a specific time and the history query as looking down the timeline of a specific piece of data.&lt;br&gt;
For example, if you had a customer in your dataset who has connections to other customers, you could see the history of that customer's connections from when they first joined your application up to the current block. If you wanted to see the connections that customer had at a specific block or over a range of blocks, that is possible, as is using the ISO-8601 date-times or durations.&lt;br&gt;&lt;br&gt;
You can build a &lt;code&gt;/history&lt;/code&gt; query using FlureeQL in JSON the same way you would with a &lt;code&gt;/block&lt;/code&gt; query. For example, if you know the subject's &lt;code&gt;_id&lt;/code&gt; you can simply hit the &lt;code&gt;/history&lt;/code&gt; endpoint like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;351843720888320&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This query will return an array of objects, each object containing the block and t numbers for that block and an array of flakes for that subject.&lt;br&gt;&lt;br&gt;
Another option is to issue a history query with a block key in order to constrain the results of the query to a specific timeframe in your data. That looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;369435906932737&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This query will return the flakes for this &lt;code&gt;_id&lt;/code&gt; up to block 4. You can also use a block range or use the ISO-8601 formatted string similar to the &lt;code&gt;/block&lt;/code&gt; queries. &lt;/p&gt;

&lt;p&gt;Using a flake format is another way you can  issue a history query. This means that you can use pieces of data to identify the subject you want to query. This works via the subject, predicate, object structure of a flake. You pass the elements you want to use to query in an array as the value of the "history" key in the query JSON. The array needs to be passed as &lt;code&gt;["subject", "predicate", "object"]&lt;/code&gt;, but you do not have to use all 3 elements in the array for the query to resolve.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that the order of these within the array is important and either a subject or a predicate is required. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, if you want to query for the history of all subjects matching the predicate object pair &lt;code&gt;dog/breed&lt;/code&gt; &lt;code&gt;"french bulldog"&lt;/code&gt; in your collection, you could query the ledger like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="s2"&gt;"dog/breed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="s2"&gt;"french bulldog"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Another way this could be done is using either a subject &lt;code&gt;_id&lt;/code&gt; with a predicate, or substitute a two-tuple which uniquely identifies a subject for the &lt;code&gt;_id&lt;/code&gt;.&lt;br&gt;
That would look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;351843720888320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="s2"&gt;"dog/favFoods"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;or with a two-tuple&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dog/name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jacques"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="s2"&gt;"dog/favFoods"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Both of these queries will return the history of the predicate &lt;code&gt;"dog/favFoods"&lt;/code&gt; for the dog specified, with either the subject &lt;code&gt;_id&lt;/code&gt; or the unique identifier of &lt;code&gt;["dog/name" "Jacques"]&lt;/code&gt; used to identify the subject you want to inspect. &lt;br&gt;
Similar to the &lt;code&gt;"/block"&lt;/code&gt; queries, a &lt;code&gt;"/history"&lt;/code&gt; query can also accept a &lt;code&gt;"prettyPrint"&lt;/code&gt; key-value pair. When true this will return the history of the subject or predicate as indicated, but will separate out the retracted and asserted flakes per block into their own arrays. That looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;351843720888320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prettyPrint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;which will return something in this type of structure:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"asserted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;351843720888320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dog/breed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"french bulldog"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retracted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the return JSON, each block containing data which matches the query is its own labeled object containing a named array for asserted and retracted.&lt;/p&gt;
&lt;h3&gt;
  
  
  "showAuth"
&lt;/h3&gt;

&lt;p&gt;There is one other extremely powerful way to use &lt;code&gt;"/history"&lt;/code&gt; queries to audit the history of who transacted the data. You can issue a &lt;code&gt;"showAuth"&lt;/code&gt; boolean key-value pair or an array of &lt;code&gt;_auth/id&lt;/code&gt; or &lt;code&gt;_auth&lt;/code&gt; subject &lt;code&gt;_id&lt;/code&gt;'s in order to filter the history query to specific auth record's transactions. Because each transaction is signed by a private key which is associated cryptographically with the &lt;code&gt;_auth/id&lt;/code&gt;, every flake in Fluree contains a record of who issued that transaction. This is the way to view that data. It looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;351843720888320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"showAuth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will return an array of block objects, each of which will contain a named array of &lt;code&gt;"auth"&lt;/code&gt; which consists of the auth's subject &lt;code&gt;_id&lt;/code&gt; and the &lt;code&gt;"_auth/id&lt;/code&gt; of the individual (man or machine) which signed that block. Which will look something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"block"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"flakes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17592186044436&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17592186044437&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17592186044438&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ferret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"t"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="mi"&gt;105553116266496&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"TexTgp1zpMkxJq1nThrgwkU5dp9wzaXA7BX"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For more information on how Fluree stores and interacts with identity and authorization, please take a look at the &lt;a href="https://docs.flur.ee/guides/1.0.0/identity/auth-records" rel="noopener noreferrer"&gt;identity section&lt;/a&gt; in the docs. &lt;/p&gt;
&lt;h2&gt;
  
  
  Wrap it up
&lt;/h2&gt;

&lt;p&gt;So that's how you can go about time traveling in Fluree. There are powerful tools which come out-of-the box which enable you to do things like query as of a specific moment in time, see how a subject evolved over time in your dataset, or get all of the data which was transacted by a specific auth record. You can read more about it in our &lt;a href="//docs.flur.ee"&gt;docs site&lt;/a&gt; or if you would prefer to engage with our community, come join us on &lt;a href="https://launchpass.com/flureedb" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more detail about this subject, you can watch our Time and Immutability Webinar on YouTube: &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CLZm3ZjvQqM"&gt;
&lt;/iframe&gt;
&lt;br&gt;
This has video has a publicly available demo  which you can review here: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fluree" rel="noopener noreferrer"&gt;
        fluree
      &lt;/a&gt; / &lt;a href="https://github.com/fluree/time-webinar" rel="noopener noreferrer"&gt;
        time-webinar
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Demo app which uses the create-react-app template for Fluree to embed a webworker with the application. This demo showcases functionality around issuing block and history queries.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Time and Immutability Webinar Demo&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This is the repository used for the demo in the &lt;a href="https://www.youtube.com/watch?v=CLZm3ZjvQqM&amp;amp;t=1972s" rel="nofollow noopener noreferrer"&gt;Time and Immutability Webinar&lt;/a&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Set up&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;To begin working with this demo app, you will need to have Fluree running locally on your machine
For detailed instruction on getting Fluree installed, please visit the &lt;a href="https://docs.flur.ee/docs/1.0.0/getting-started/installation" rel="nofollow noopener noreferrer"&gt;installation page on the docs site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You will also need to have &lt;a href="https://nodejs.org/en/download/" rel="nofollow noopener noreferrer"&gt;Node.js&lt;/a&gt; installed on your machine.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/fluree/time-webinar/tree/main/data" rel="noopener noreferrer"&gt;data folder&lt;/a&gt; contains the seed data for using this application as it is shown in the webinar.
To get the data loaded into your Fluree instance, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Admin UI and create a ledger called time/webinar.&lt;/li&gt;
&lt;li&gt;Using either the Admin UI or a REST client of your choosing (Postman, Insomnia, etc.) transact the files in the data/ folder, in order, to your ledger
&lt;ul&gt;
&lt;li&gt;This will transact the schema&lt;/li&gt;
&lt;li&gt;The airports and tags for the statuses&lt;/li&gt;
&lt;li&gt;The flight.json files…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/fluree/time-webinar" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>database</category>
      <category>blockchain</category>
      <category>immutability</category>
      <category>fluree</category>
    </item>
  </channel>
</rss>
