diff --git a/.circleci/config.yml b/.circleci/config.yml
index 36ba30e462e2fef5c4558b6be64cb62517255636..76122817b5443d2bc8045fa56a8b1c796a1a658d 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -126,7 +126,7 @@ executors:
      working_directory: /home/circleci/metabase/metabase/
      docker:
        - image: metabase/ci:circleci-java-11-clj-1.10.3.929-07-27-2021-node-browsers
-       - image: circleci/mongo:4.0
+       - image: circleci/mongo:5.0
 
   presto-186:
     working_directory: /home/circleci/metabase/metabase/
@@ -196,11 +196,11 @@ executors:
     resource_class: large
 
 
-  fe-mongo-4:
+  fe-mongo-5:
     working_directory: /home/circleci/metabase/metabase/
     docker:
       - image: metabase/ci:circleci-java-11-clj-1.10.3.929-07-27-2021-node-browsers
-      - image: metabase/qa-databases:mongo-sample-4.0
+      - image: metabase/qa-databases:mongo-sample-5.0
 
   fe-postgres-12:
     working_directory: /home/circleci/metabase/metabase/
@@ -1266,10 +1266,10 @@ workflows:
           source-folder: << matrix.folder >>
 
       - fe-tests-cypress:
-          name: e2e-tests-mongo-4-<< matrix.edition >>
+          name: e2e-tests-mongo-5-<< matrix.edition >>
           requires:
             - build-uberjar-<< matrix.edition >>
-          e: fe-mongo-4
+          e: fe-mongo-5
           cypress-group: "mongo"
           source-folder: mongo
           qa-db: true
diff --git a/frontend/test/metabase-db/mongo/query.cy.spec.js b/frontend/test/metabase-db/mongo/query.cy.spec.js
index d0fe9073e8401c79d4db59902e551ff5cc0df566..10082c04edf09fe723d01875f98bd9fc2a0e5f00 100644
--- a/frontend/test/metabase-db/mongo/query.cy.spec.js
+++ b/frontend/test/metabase-db/mongo/query.cy.spec.js
@@ -104,5 +104,5 @@ function writeNativeMongoQuery() {
     parseSpecialCharSequences: false,
   });
   cy.get(".NativeQueryEditor .Icon-play").click();
-  cy.findByText("18,760");
+  cy.findByText("42");
 }
diff --git a/modules/drivers/mongo/src/metabase/driver/mongo.clj b/modules/drivers/mongo/src/metabase/driver/mongo.clj
index 78e4833164adac457bca3b4a289ce749d1b541d6..a8bdd5f2b948ae5539a92a7bb70fe67d6264358e 100644
--- a/modules/drivers/mongo/src/metabase/driver/mongo.clj
+++ b/modules/drivers/mongo/src/metabase/driver/mongo.clj
@@ -18,6 +18,7 @@
             [monger.collection :as mc]
             [monger.command :as cmd]
             [monger.conversion :as m.conversion]
+            [monger.core :as mg]
             [monger.db :as mdb]
             monger.json
             [schema.core :as s]
@@ -174,8 +175,9 @@
 (defmethod driver/describe-database :mongo
   [_ database]
   (with-mongo-connection [^com.mongodb.DB conn database]
-    {:tables (set (for [collection (disj (mdb/get-collection-names conn) "system.indexes")]
-                    {:schema nil, :name collection}))}))
+    {:tables  (set (for [collection (disj (mdb/get-collection-names conn) "system.indexes")]
+                    {:schema nil, :name collection}))
+     :version (get (mg/command conn {:buildInfo 1}) "version")}))
 
 (defn- table-sample-column-info
   "Sample the rows (i.e., documents) in `table` and return a map of information about the column keys we found in that
@@ -215,6 +217,13 @@
                  :native-parameters]]
   (defmethod driver/supports? [:mongo feature] [_ _] true))
 
+(defmethod driver/database-supports? [:mongo :expressions] [_ _ db]
+  (let [version (some-> (get-in db [:details :version])
+                        (str/split #"\.")
+                        first
+                        Integer/parseInt)]
+    (and (some? version) (<= 5 version))))
+
 (defmethod driver/mbql->native :mongo
   [_ query]
   (qp/mbql->native query))
diff --git a/modules/drivers/mongo/src/metabase/driver/mongo/query_processor.clj b/modules/drivers/mongo/src/metabase/driver/mongo/query_processor.clj
index 3b99478c65f73f19e9e30c541c7d21d83b989985..40716c2c15ec543ae320ed45660af4949b98edfb 100644
--- a/modules/drivers/mongo/src/metabase/driver/mongo/query_processor.clj
+++ b/modules/drivers/mongo/src/metabase/driver/mongo/query_processor.clj
@@ -105,10 +105,18 @@
   [field]
   (field->name field \.))
 
+(defmethod ->lvalue :expression
+  [[_ expression-name]]
+  expression-name)
+
 (defmethod ->rvalue :default
   [x]
   x)
 
+(defmethod ->rvalue :expression
+  [[_ expression-name]]
+  (->rvalue (mbql.u/expression-with-name (:query *query*) expression-name)))
+
 (defmethod ->rvalue (class Field)
   [{coercion :coercion_strategy, :as field}]
   (let [field-name (str \$ (field->name field "."))]
@@ -284,6 +292,77 @@
             (u.date/add unit amount)
             (u.date/bucket unit)))))))
 
+;;; ---------------------------------------------------- functions ---------------------------------------------------
+
+;; It doesn't make 100% sense to have lvalues for all these but it's a formal requirement
+
+(defmethod ->lvalue :avg       [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :stddev    [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :sum       [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :min       [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :max       [[_ inp]] (->lvalue inp))
+
+(defmethod ->lvalue :floor     [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :ceil      [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :round     [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :abs       [[_ inp]] (->lvalue inp))
+
+(defmethod ->lvalue :log       [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :exp       [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :sqrt      [[_ inp]] (->lvalue inp))
+
+(defmethod ->lvalue :trim      [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :ltrim     [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :rtrim     [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :upper     [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :lower     [[_ inp]] (->lvalue inp))
+(defmethod ->lvalue :length    [[_ inp]] (->lvalue inp))
+
+(defmethod ->lvalue :power     [[_ & args]] (->lvalue (first args)))
+(defmethod ->lvalue :replace   [[_ & args]] (->lvalue (first args)))
+(defmethod ->lvalue :concat    [[_ & args]] (->lvalue (first args)))
+(defmethod ->lvalue :substring [[_ & args]] (->lvalue (first args)))
+
+(defmethod ->lvalue :+ [[_ & args]] (->lvalue (first args)))
+(defmethod ->lvalue :- [[_ & args]] (->lvalue (first args)))
+(defmethod ->lvalue :* [[_ & args]] (->lvalue (first args)))
+(defmethod ->lvalue :/ [[_ & args]] (->lvalue (first args)))
+
+(defmethod ->rvalue :coalesce [[_ & args]] (->lvalue (first args)))
+
+(defmethod ->rvalue :avg       [[_ inp]] {"$avg" (->rvalue inp)})
+(defmethod ->rvalue :stddev    [[_ inp]] {"$stdDevPop" (->rvalue inp)})
+(defmethod ->rvalue :sum       [[_ inp]] {"$sum" (->rvalue inp)})
+(defmethod ->rvalue :min       [[_ inp]] {"$min" (->rvalue inp)})
+(defmethod ->rvalue :max       [[_ inp]] {"$max" (->rvalue inp)})
+
+(defmethod ->rvalue :floor     [[_ inp]] {"$floor" (->rvalue inp)})
+(defmethod ->rvalue :ceil      [[_ inp]] {"$ceil" (->rvalue inp)})
+(defmethod ->rvalue :round     [[_ inp]] {"$round" (->rvalue inp)})
+(defmethod ->rvalue :abs       [[_ inp]] {"$abs" (->rvalue inp)})
+
+(defmethod ->rvalue :log       [[_ inp]] {"$log10" (->rvalue inp)})
+(defmethod ->rvalue :exp       [[_ inp]] {"$exp" (->rvalue inp)})
+(defmethod ->rvalue :sqrt      [[_ inp]] {"$sqrt" (->rvalue inp)})
+
+(defmethod ->rvalue :trim      [[_ inp]] {"$trim" (->rvalue inp)})
+(defmethod ->rvalue :ltrim     [[_ inp]] {"$ltrim" (->rvalue inp)})
+(defmethod ->rvalue :rtrim     [[_ inp]] {"$rtrim" (->rvalue inp)})
+(defmethod ->rvalue :upper     [[_ inp]] {"$toUpper" (->rvalue inp)})
+(defmethod ->rvalue :lower     [[_ inp]] {"$toLower" (->rvalue inp)})
+(defmethod ->rvalue :length    [[_ inp]] {"$strLenCP" (->rvalue inp)})
+
+(defmethod ->rvalue :power     [[_ & args]] {"$pow" (mapv ->rvalue args)})
+(defmethod ->rvalue :replace   [[_ & args]] {"$replaceAll" (mapv ->rvalue args)})
+(defmethod ->rvalue :concat    [[_ & args]] {"$concat" (mapv ->rvalue args)})
+(defmethod ->rvalue :substring [[_ & args]] {"$substrCP" (mapv ->rvalue args)})
+
+(defmethod ->rvalue :+ [[_ & args]] {"$add" (mapv ->rvalue args)})
+(defmethod ->rvalue :- [[_ & args]] {"$subtract" (mapv ->rvalue args)})
+(defmethod ->rvalue :* [[_ & args]] {"$multiply" (mapv ->rvalue args)})
+(defmethod ->rvalue :/ [[_ & args]] {"$divide" (mapv ->rvalue args)})
+
+(defmethod ->rvalue :coalesce [[_ & args]] {"$ifNull" (mapv ->rvalue args)})
 
 ;;; +----------------------------------------------------------------------------------------------------------------+
 ;;; |                                               CLAUSE APPLICATION                                               |
@@ -645,7 +724,6 @@
                                                           {$skip offset}))
                                                       {$limit items-per-page}]))))
 
-
 ;;; +----------------------------------------------------------------------------------------------------------------+
 ;;; |                                                 Process & Run                                                  |
 ;;; +----------------------------------------------------------------------------------------------------------------+
diff --git a/modules/drivers/mongo/test/metabase/driver/mongo/query_processor_test.clj b/modules/drivers/mongo/test/metabase/driver/mongo/query_processor_test.clj
index 1e1d91c094f6a50e265dfac6065d7fae9cbb3dde..f88d3bafd2162884249af14024f68d26acb44f42 100644
--- a/modules/drivers/mongo/test/metabase/driver/mongo/query_processor_test.clj
+++ b/modules/drivers/mongo/test/metabase/driver/mongo/query_processor_test.clj
@@ -153,6 +153,70 @@
                                [:distinct $price]]
                  :limit       5})))))))
 
+(defn- extract-projections [projections q]
+  (select-keys (get-in q [:query 0 "$project"]) projections))
+
+(deftest expressions-test
+  (mt/test-driver :mongo
+    (testing "Should be able to deal with expressions (#9382 is for BQ but we're doing it for mongo too)"
+      (is (= {"bob" "$latitude", "cobb" "$name"}
+             (extract-projections
+               ["bob" "cobb"]
+               (qp/query->native
+                 (mt/mbql-query venues
+                                {:fields      [[:expression "bob"] [:expression "cobb"]]
+                                 :expressions {:bob   [:field $latitude nil]
+                                               :cobb [:field $name nil]}
+                                 :limit       5}))))))
+    (testing "Should be able to deal with 1-arity functions"
+      (is (= {"cobb" {"$toUpper" "$name"},
+              "bob" {"$abs" "$latitude"} }
+             (extract-projections
+               ["bob" "cobb"]
+               (qp/query->native
+                 (mt/mbql-query venues
+                                {:filters     [[:expression "bob"] [:expression "cobb"]]
+                                 :expressions {:bob   [:abs $latitude]
+                                               :cobb [:upper $name]}
+                                 :limit       5}))))))
+    (testing "Should be able to deal with 2-arity functions"
+      (is (= {"bob" {"$add" ["$price" 300]}}
+             (extract-projections
+               ["bob"]
+               (qp/query->native
+                 (mt/mbql-query venues
+                                {:filters     [[:expression "bob"] [:expression "cobb"]]
+                                 :expressions {:bob   [:+ $price 300]}
+                                 :limit       5}))))))
+    (testing "Should be able to deal with a little indirection"
+      (is (= {"bob" {"$abs" {"$subtract" ["$price" 300]}}}
+             (extract-projections
+               ["bob"]
+               (qp/query->native
+                 (mt/mbql-query venues
+                                {:filters     [[:expression "bob"] [:expression "cobb"]]
+                                 :expressions {:bob   [:abs [:- $price 300]]}
+                                 :limit       5}))))))
+    (testing "Should be able to deal with a little indirection, with an expression in"
+      (is (= {"bob" {"$abs" "$latitude"},
+              "cobb" {"$ceil" {"$abs" "$latitude"}}}
+             (extract-projections
+               ["bob" "cobb"]
+               (qp/query->native
+                 (mt/mbql-query venues
+                                {:filters     [[:expression "bob"] [:expression "cobb"]]
+                                 :expressions {:bob  [:abs $latitude]
+                                               :cobb [:ceil [:expression "bob"]]}
+                                 :limit       5}))))))
+    (testing "Should be able to deal with coalescing"
+      (is (= {"bob" {"$ifNull" ["$latitude" "$price"]}}
+             (extract-projections
+               ["bob"]
+               (qp/query->native
+                 (mt/mbql-query venues
+                                {:expressions {:bob [:coalesce [:field $latitude nil] [:field $price nil]]}
+                                 :limit       5}))))))))
+
 (deftest compile-time-interval-test
   (mt/test-driver :mongo
     (testing "Make sure time-intervals work the way they're supposed to."
diff --git a/modules/drivers/mongo/test/metabase/driver/mongo_test.clj b/modules/drivers/mongo/test/metabase/driver/mongo_test.clj
index 7300f05cd2a6030ac8e5f690a176fbe28720f846..f44ae69ae5f3ff4e5887c39adb74579e3e32c863 100644
--- a/modules/drivers/mongo/test/metabase/driver/mongo_test.clj
+++ b/modules/drivers/mongo/test/metabase/driver/mongo_test.clj
@@ -61,10 +61,33 @@
                                                 :expected true}
                                                {:details  {:conn-uri "mongodb://localhost:3000/bad-db-name?connectTimeoutMS=50"}
                                                 :expected false}]]
-      (testing (str "connect with " details)
-        (is (= expected
-               (driver.u/can-connect-with-details? :mongo details))
-            (str message))))))
+     (testing (str "connect with " details)
+       (is (= expected
+              (driver.u/can-connect-with-details? :mongo details))
+           (str message))))))
+
+(deftest database-supports?-test
+(mt/test-driver
+   :mongo
+   (doseq [{:keys [details expected]} [{:details  {:host    "localhost"
+                                                   :port    3000
+                                                   :dbname  "bad-db-name"
+                                                   :version "5.0.0"}
+                                        :expected true}
+                                       {:details  {}
+                                        :expected false}
+                                       {:details  {:version nil}
+                                        :expected false}
+                                       {:details  {:host    "localhost"
+                                                   :port    27017
+                                                   :dbname  "metabase-test"
+                                                   :version "2.2134234.lol"}
+                                        :expected false}]]
+     (testing (str "connect with " details)
+       (is (= expected
+              (let [db (db/insert! Database {:name "dummy", :engine "mongo", :details details})]
+                (driver/database-supports? :mongo :expressions db))))))))
+
 
 (def ^:private native-query
   "[{\"$project\": {\"_id\": \"$_id\"}},
@@ -96,11 +119,11 @@
 
 (deftest describe-database-test
   (mt/test-driver :mongo
-    (is (= {:tables #{{:schema nil, :name "checkins"}
-                      {:schema nil, :name "categories"}
-                      {:schema nil, :name "users"}
-                      {:schema nil, :name "venues"}}}
-           (driver/describe-database :mongo (mt/db))))))
+    (is (= #{{:schema nil, :name "checkins"}
+             {:schema nil, :name "categories"}
+             {:schema nil, :name "users"}
+             {:schema nil, :name "venues"}}
+             (:tables (driver/describe-database :mongo (mt/db)))))))
 
 (deftest describe-table-test
   (mt/test-driver :mongo
diff --git a/src/metabase/sync/interface.clj b/src/metabase/sync/interface.clj
index 33747a9247f40dd4323558bde94707270338b0fa..bfab0baeb2faf5d98d93c5b6f1f9917519330cc5 100644
--- a/src/metabase/sync/interface.clj
+++ b/src/metabase/sync/interface.clj
@@ -17,7 +17,8 @@
 
 (def DatabaseMetadata
   "Schema for the expected output of `describe-database`."
-  {:tables #{DatabaseMetadataTable}})
+  {:tables                   #{DatabaseMetadataTable}
+   (s/optional-key :version) (s/maybe su/NonBlankString)})
 
 (def TableMetadataField
   "Schema for a given Field as provided in `describe-table`."
diff --git a/src/metabase/sync/sync_metadata.clj b/src/metabase/sync/sync_metadata.clj
index fe7f29bc58f3aa99eaa9493b8087e1097a51a891..f612cd49cc5283325f99c2fbaf5e71ffea17eb40 100644
--- a/src/metabase/sync/sync_metadata.clj
+++ b/src/metabase/sync/sync_metadata.clj
@@ -34,7 +34,7 @@
 (def ^:private sync-steps
   [(sync-util/create-sync-step "sync-timezone" sync-tz/sync-timezone! sync-timezone-summary)
    ;; Make sure the relevant table models are up-to-date
-   (sync-util/create-sync-step "sync-tables" sync-tables/sync-tables! sync-tables-summary)
+   (sync-util/create-sync-step "sync-tables" sync-tables/sync-tables-and-database! sync-tables-summary)
    ;; Now for each table, sync the fields
    (sync-util/create-sync-step "sync-fields" sync-fields/sync-fields! sync-fields-summary)
    ;; Now for each table, sync the FKS. This has to be done after syncing all the fields to make sure target fields exist
diff --git a/src/metabase/sync/sync_metadata/tables.clj b/src/metabase/sync/sync_metadata/tables.clj
index 92f2392e0e21852004f1f465ba8e5df1a3f0e0ff..5f3d4045bfd50fc81f44352dd9c5ea5d4745e946 100644
--- a/src/metabase/sync/sync_metadata/tables.clj
+++ b/src/metabase/sync/sync_metadata/tables.clj
@@ -3,6 +3,7 @@
   (:require [clojure.data :as data]
             [clojure.string :as str]
             [clojure.tools.logging :as log]
+            [metabase.models.database :as db-model :refer [Database]]
             [metabase.models.humanization :as humanization]
             [metabase.models.table :as table :refer [Table]]
             [metabase.sync.fetch-metadata :as fetch-metadata]
@@ -80,6 +81,14 @@
 
 ;;; ---------------------------------------------------- Syncing -----------------------------------------------------
 
+(s/defn ^:private update-database-metadata!
+  "If there is a version in the db-metadata update the DB to have that in the DB model"
+  [database :- i/DatabaseInstance db-metadata :- i/DatabaseMetadata]
+  (log/info (trs "Found new version for DB: {0}" (:version db-metadata)))
+  (db/update! Database (u/the-id database)
+              :details
+              (assoc (:details database) :version (:version db-metadata))))
+
 ;; TODO - should we make this logic case-insensitive like it is for fields?
 
 (s/defn ^:private create-or-reactivate-tables!
@@ -137,10 +146,11 @@
                         :description description))))
 
 
-(s/defn ^:private db-metadata :- #{i/DatabaseMetadataTable}
-  "Return information about `database` by calling its driver's implementation of `describe-database`."
-  [database :- i/DatabaseInstance]
-  (set (for [table (:tables (fetch-metadata/db-metadata database))
+(s/defn ^:private table-set :- #{i/DatabaseMetadataTable}
+  "So there exist tables for the user and metabase metadata tables for internal usage by metabase.
+  Get set of user tables only, excluding metabase metadata tables."
+  [db-metadata :- i/DatabaseMetadata]
+  (set (for [table (:tables db-metadata)
              :when (not (metabase-metadata/is-metabase-metadata-table? table))]
          table)))
 
@@ -152,19 +162,26 @@
               :db_id  (u/the-id database)
               :active true))))
 
-(s/defn sync-tables!
+(s/defn sync-tables-and-database!
   "Sync the Tables recorded in the Metabase application database with the ones obtained by calling `database`'s driver's
-  implementation of `describe-database`."
+  implementation of `describe-database`.
+  Also syncs the database metadata taken from describe-database if there is any"
   [database :- i/DatabaseInstance]
   ;; determine what's changed between what info we have and what's in the DB
-  (let [db-metadata             (db-metadata database)
+  (let [db-metadata             (fetch-metadata/db-metadata database)
+        db-tables               (table-set db-metadata)
         our-metadata            (our-metadata database)
         strip-desc              (fn [metadata]
                                   (set (map #(dissoc % :description) metadata)))
         [new-tables old-tables] (data/diff
-                                  (strip-desc db-metadata)
+                                  (strip-desc db-tables)
                                   (strip-desc our-metadata))
-        [changed-tables]        (data/diff db-metadata our-metadata)]
+        [changed-tables]        (data/diff db-tables our-metadata)]
+    ;; update database metadata from database
+    (when (some? (:version db-metadata))
+      (sync-util/with-error-handling (format "Error creating/reactivating tables for %s"
+                                             (sync-util/name-for-logging database))
+        (update-database-metadata! database db-metadata)))
     ;; create new tables as needed or mark them as active again
     (when (seq new-tables)
       (sync-util/with-error-handling (format "Error creating/reactivating tables for %s"
diff --git a/test/metabase/sync/sync_metadata/comments_test.clj b/test/metabase/sync/sync_metadata/comments_test.clj
index 28dda64b529fe98154956fee2eccc9c73d8cc29c..0a3b3d75a484593d4cd3fbe72a72023d32efdf5f 100644
--- a/test/metabase/sync/sync_metadata/comments_test.clj
+++ b/test/metabase/sync/sync_metadata/comments_test.clj
@@ -103,7 +103,7 @@
           ;; change the description in metabase while the source table comment remains the same
           (db/update-where! Table {:id (mt/id "table_with_updated_desc")}, :description "updated table description")
           ;; now sync the DB again, this should NOT overwrite the manually updated description
-          (sync-tables/sync-tables! (mt/db))
+          (sync-tables/sync-tables-and-database! (mt/db))
           (is (= #{{:name (mt/format-name "table_with_updated_desc"), :description "updated table description"}}
                  (db->tables (mt/db)))))))))
 
@@ -114,6 +114,6 @@
         ;; modify the source DB to add the comment and resync
         (driver/notify-database-updated driver/*driver* (mt/db))
         (tx/create-db! driver/*driver* (basic-table "table_with_comment_after_sync" "added comment"))
-        (sync-tables/sync-tables! (mt/db))
+        (sync-tables/sync-tables-and-database! (mt/db))
         (is (= #{{:name (mt/format-name "table_with_comment_after_sync"), :description "added comment"}}
                (db->tables (mt/db))))))))