如何在Clojure中按给定日期过滤JSON数据?

如何在Clojure中按给定日期过滤JSON数据?,clojure,Clojure,我有很多JSON对象,我正在尝试按日期过滤这些对象。使用Cheshire.core从几个JSON文件解析这些对象,这意味着JSON对象位于一个集合中。日期以以下格式“YYYY-MM-DD”(如2015-01-10)传递。我已尝试使用过滤器,并包含?函数来执行此操作,但到目前为止我没有运气。我如何根据我选择的日期过滤这些JSON对象 当前Clojure代码: (def filter-by-date? (fn [orders-data date-chosen] (contains

我有很多JSON对象,我正在尝试按日期过滤这些对象。使用Cheshire.core从几个JSON文件解析这些对象,这意味着JSON对象位于一个集合中。日期以以下格式“YYYY-MM-DD”(如2015-01-10)传递。我已尝试使用过滤器,并包含?函数来执行此操作,但到目前为止我没有运气。我如何根据我选择的日期过滤这些JSON对象

当前Clojure代码:

(def filter-by-date?
    (fn [orders-data date-chosen]
      (contains? (get (get orders-data :date) :date) date-chosen)))


(prn (filter (filter-by-date? orders-data "2017-12-25")))
JSON对象示例:

{
    "id":"05d8d404-b3f6-46d1-a0f9-dbdab7e0261f",
    "date":{
        "date":"2015-01-10T19:11:41.000Z"
    },
    "total":{
        "GBP":57.45
    }
}
使用Cheshire解析后的JSON:

[({:id "05d8d404-b3f6-46d1-a0f9-dbdab7e0261f", 
:date {:date "2015-01-10T19:11:41.000Z"}, 
:total {:GBP 57.45}}) ({:id "325bd04-b3f6-46d1-a0f9-dbdab7e0261f", 
:date {:date "2015-02-23T10:15:14.000Z"}, 
:total {:GBP 32.90}})]

首先,我假设您首先将JSON解析为如下内容:

(def parsed-JSON {:id "05d8d404-b3f6-46d1-a0f9-dbdab7e0261f",
                  :date {:date "2015-01-10T19:11:41.000Z"},
                  :total {:GBP 57.45}})
主要问题是,JSON中存储的日期包含时间信息,因此您无法直接使用相等性来检查它

您可以通过使用
clojure.string/以?
开头来检查前缀来解决这个问题。我在这里使用
s/
作为
clojure.string的别名:

(defn filter-by-date [date jsons]
  (filter #(s/starts-with? (get-in % [:date :date]) date)
          jsons))
你很接近,但我做了一些改变:

  • 你不能像那样使用
    contains?
    。从
    包含的文档中:
    如果给定集合中存在密钥,则返回true,否则返回false
    。它不能用于检查子字符串;它用于测试集合中是否存在密钥

  • 在后缀版本中使用
    -in
    访问嵌套结构,而不是使用多个调用。我在这里使用的是
    (get in…
    ,而不是
    (get(get…)

  • 您正在使用
    (def…(fn[])
    ,这会使事情变得比需要的更复杂,尽管
    defn
    也增加了一些东西


要处理新信息,您只需首先展平包含JSON的嵌套序列即可:

(->> nested-json-colls ; The data at the bottom of the question
     (flatten)
     (filter-by-date "2015-01-10")) 

首先,我假设您首先将JSON解析为如下内容:

(def parsed-JSON {:id "05d8d404-b3f6-46d1-a0f9-dbdab7e0261f",
                  :date {:date "2015-01-10T19:11:41.000Z"},
                  :total {:GBP 57.45}})
主要问题是,JSON中存储的日期包含时间信息,因此您无法直接使用相等性来检查它

您可以通过使用
clojure.string/以?
开头来检查前缀来解决这个问题。我在这里使用
s/
作为
clojure.string的别名:

(defn filter-by-date [date jsons]
  (filter #(s/starts-with? (get-in % [:date :date]) date)
          jsons))
你很接近,但我做了一些改变:

  • 你不能像那样使用
    contains?
    。从
    包含的文档中:
    如果给定集合中存在密钥,则返回true,否则返回false
    。它不能用于检查子字符串;它用于测试集合中是否存在密钥

  • 在后缀版本中使用
    -in
    访问嵌套结构,而不是使用多个调用。我在这里使用的是
    (get in…
    ,而不是
    (get(get…)

  • 您正在使用
    (def…(fn[])
    ,这会使事情变得比需要的更复杂,尽管
    defn
    也增加了一些东西


要处理新信息,您只需首先展平包含JSON的嵌套序列即可:

(->> nested-json-colls ; The data at the bottom of the question
     (flatten)
     (filter-by-date "2015-01-10")) 
您可以使用任何DateTime库(如joda time)将日期字符串转换为日期对象,然后根据需要进行适当的筛选

您可以使用任何日期时间库(如joda time)将日期字符串转换为日期对象,然后根据需要进行适当的筛选。

具有解析字符串和比较日期时间对象的功能。所以你可以这样做:

(ns filter-by-time-example
  (:require [clj-time.coerce :as tc]
            [clj-time.core :as t]))

(def objs [{"id" nil
            "date" {"date" "2015-01-12T19:11:41.000Z"}
            "total" nil}
           {"id" "05d8d404-b3f6-46d1-a0f9-dbdab7e0261f"
            "date" {"date" "2015-01-10T19:11:41.000Z"}
            "total" {"GBP" :57.45}}
           {"id" nil
            "date" {"date" "2015-01-11T19:11:41.000Z"}
            "total" nil}])

(defn filter-by-day
  [objs y m d]
  (let [start (t/date-time y m d)
        end (t/plus start (t/days 1))]
    (filter #(->> (get-in % ["date" "date"])
                  tc/from-string
                  (t/within? start end)) objs)))

(clojure.pprint/pprint (filter-by-day objs 2015 1 10)) ;; Returns second obj
如果要重复执行此操作(例如,多天),可以使用以下命令将集合中的所有日期解析为日期时间对象:

(map #(update-in % ["date" "date"] tc/from-string) objs)
然后只使用该集合以避免重复解析步骤。

具有解析字符串和比较日期时间对象的功能。所以你可以这样做:

(ns filter-by-time-example
  (:require [clj-time.coerce :as tc]
            [clj-time.core :as t]))

(def objs [{"id" nil
            "date" {"date" "2015-01-12T19:11:41.000Z"}
            "total" nil}
           {"id" "05d8d404-b3f6-46d1-a0f9-dbdab7e0261f"
            "date" {"date" "2015-01-10T19:11:41.000Z"}
            "total" {"GBP" :57.45}}
           {"id" nil
            "date" {"date" "2015-01-11T19:11:41.000Z"}
            "total" nil}])

(defn filter-by-day
  [objs y m d]
  (let [start (t/date-time y m d)
        end (t/plus start (t/days 1))]
    (filter #(->> (get-in % ["date" "date"])
                  tc/from-string
                  (t/within? start end)) objs)))

(clojure.pprint/pprint (filter-by-day objs 2015 1 10)) ;; Returns second obj
(ns filter-by-time-example
  (:require [clj-time.format :as f]
            [clj-time.core :as t]
            [cheshire.core :as cheshire]))

(->> json-coll
     (map (fn [json] (cheshire/parse-string json true)))
     (map (fn [record] (assoc record :dt-date (f/format (get-in record [:date :date])))))
     (filter (fn [record] (t/after? (tf/format "2017-12-25") (:dt-date record))))
     (map (fn [record] (dissoc record :dt-date))))
如果要重复执行此操作(例如,多天),可以使用以下命令将集合中的所有日期解析为日期时间对象:

(map #(update-in % ["date" "date"] tc/from-string) objs)
然后只使用该集合,以避免重复解析步骤

(ns filter-by-time-example
  (:require [clj-time.format :as f]
            [clj-time.core :as t]
            [cheshire.core :as cheshire]))

(->> json-coll
     (map (fn [json] (cheshire/parse-string json true)))
     (map (fn [record] (assoc record :dt-date (f/format (get-in record [:date :date])))))
     (filter (fn [record] (t/after? (tf/format "2017-12-25") (:dt-date record))))
     (map (fn [record] (dissoc record :dt-date))))
也许是这样的?您可能需要为您的用例更改过滤器,但是作为
:dt time
现在是一个
jodo.DateTime
您可以利用所有
clj time
谓词


也许是这样的?您可能需要为您的用例更改过滤器,但是作为
:dt time
现在是一个
jodo.DateTime
您可以利用所有
clj time
谓词。

您好,谢谢您的回答。我尝试使用您的解决方案,但在尝试打印“ret”时遇到了NullPointerException,json必须没有正确的键。例如:`(filter#(str/includes?(get in%[:date:foo])“2015-01-”)orders`给出NPE,因为原始json没有
:foo
键。我已经更新了我的问题,加入了一个示例,说明在使用cheshire解析后json是如何构造的json数据必须是一个集合。如果您将示例中解析的json包含在一个向量中,它将起作用。
(filter#(str/includes?(get in%[:date:date])“2015-01-”[{:id“05d8d404-b3f6-46d1-a0f9-dbdab7e0261f”:date{:date 2015-01-10T19:11:41.000Z}:总计{:GBP 57.45}}
Hi谢谢您的回答。我尝试使用您的解决方案,但在尝试打印“ret”时遇到了NullPointerException,json必须没有正确的键。例如:`(filter#(str/includes?(get in%[:date:foo])“2015-01-”)orders`给出NPE,因为原始json没有
:foo
键。我已经更新了我的问题,加入了一个示例,说明在使用cheshire解析后json是如何构造的json数据必须是一个集合。如果您将示例中解析的json包含在一个向量中,它将起作用。
(filter#(str/includes?(get in%[:date:date])“2015-01-”[{:id“05d8d404-b3f6-46d1-a0f9-dbdab7e0261f”:date{:date 2015-01-10T19:11:41.000Z}:总计{:GBP 57.45}
Hi