【问题标题】:Haskell sqlite3 jsonHaskell sqlite3 json
【发布时间】:2019-05-16 03:45:07
【问题描述】:

我正在尝试创建一个简单的 Haskell 应用程序,该应用程序从 API 获取数据,然后将它们插入数据库 (sqlite3)。我已经成功地从我的 API 中获取数据并创建了数据库。但是,我目前面临的问题是如何从 JSON 中提取这些数据并将其插入到数据库中。我无法分享所有细节,这就是我修改类型(数据)结构的原因。示例 API 响应:

[{"name":"John","surname":"Terry","workPlace":"Bank","accountBalance":124344.08,"age":44}]

Person 数据类型及其实例(用于提取):

    data Person = Person
               {

                  name :: Text, 
                  surname :: Text,
                  workPlace :: Text, 
                  accountBalance :: Rational, 
                  age :: Integer 
               }
               deriving (Eq, Show, Read, Generic, ToJSON )



instance FromJSON Person where
   parseJSON (Object v) = p <$> n <*> s <*> w <*> acc <*> a
       where p = Person             
             n = v .: "name"
             s = v .: "surname"
             w = v .: "workPlace"
             acc = v .: "accountBalance"
             a = v .: "age"
   -- A non-Object value is of the wrong type, so fail.
   parseJSON _ = mzero

提前致谢。

【问题讨论】:

  • 您可以像将任何内容插入数据库一样进行操作。一旦你有了你需要的值,来源就无关紧要了。
  • 你能把你的问题范围缩小一点,并提供更完整的细节吗?根据我的阅读,您已经拥有Person 类型的值,并希望在某个未指定的数据库库中创建一个数据库条目,可能是sqlite-simple,可能是sqlite,或sqlite-direct,或者可能是其他东西。似乎关于 JSON 的讨论都是多余的。
  • 非常感谢您的回复。问题是,我需要将 json 中的值分配给变量,以便我可以将存储在这些变量中的值插入到数据库中,对吗?我的问题是,每当我尝试将 json 转换为对象时,我都会以 IO() 格式结束,而且我不知道接下来我应该按顺序做什么(并且它会使其可访问。)以提供我的数据库与数据。我是 Haskell 的初学者,所以我可能会遗漏一些东西。
  • 如果您的问题与 IO 有关,请编辑问题并包含您正在执行 IO 的代码。如果您有可以将 Person 写入数据库的代码,请将其也包含在内。
  • 这不是 IO 问题。 IO 是我要做的最后一件事,但它仍然没有改变这样一个事实,即我想了解的是如何从 JSON 中提取数据,以便将其分配给变量,然后插入到数据库中。谢谢。

标签: json sqlite haskell


【解决方案1】:

我目前面临的问题是如何从 JSON 中提取这些数据并将其插入到数据库中。

这是两个不同的问题。

  1. 您的类型有一个FromJSON 实例,因此您只需decodeeitherDecode 将您的JSON 解析为Person 类型:

     case eitherDecode person_json of
        Left err     -> error err
        Right person -> insertPersonIntoDB person
    
  2. 您尚未选择 sqlite 库。选择一个并阅读如何使用它。我选择了 sqlite-simple 可以这样使用:

     do
     conn <- open "test.db"
     execute_ conn "CREATE TABLE IF NOT EXISTS people\
                   \ (name TEXT, surname TEXT, workPlace TEXT,\
                   \ accountBalance INTEGER, age INTEGER)"
     execute conn "INSERT INTO people \
                  \(name,surname,workPlace,accountBalance,age)\
                  \ VALUES (?,?,?,?,?)"
             (name,surname,workPlace,accountBalance,age)
     close conn
    

后来,你在评论中说:

我需要将 json 中的值赋给变量

这就是解码器所做的,它将 JSON 解析为 Person 值,通过对 Person 的模式匹配,我们可以获得每个 JSON 字段的变量。例如:

printPersonTuple (Person nm sur wk acct years) =
    print (nm,sur,wk,acct,years)

这样我就可以将存储在这些变量中的值插入到数据库中

是的,一旦你有了变量名,或者只是一个 ToRow 实例(阅读 sqlite-simple 文档),你就可以将值插入到数据库中。

而我的问题是,每当我尝试将 json 转换为对象时,我都会以 IO() 格式结束

嗯,这是一个与您问题中的任何内容非常不同的问题。如果您感到困惑,请将其作为另一个问题发布。

结论

您似乎有几个问题,例如理解 IO、将问题分解为子组件、在解析后使用值、选择和挖掘数据库库。请参阅下面的完整示例,但鉴于此要学习的内容列表,它可能不会完全阐明 - 请务必提出后续问题,而不是作为此答案的 cmets,而是作为与此答案分开的新问题。

{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
import GHC.Generics                     -- So you can derive 'Generic'
import Data.Aeson                       -- JSON
import Database.SQLite.Simple           -- Databse ops
import Data.Text (Text,unpack)
import qualified Data.ByteString.Lazy.Char8 as BC -- Just for prettier debugging

-- The type you are receiving from JSON
data Person = Person
           { name           :: Text
           , surname        :: Text
           , workPlace      :: Text
           , accountBalance :: Integer
           , age            :: Integer
           }
           deriving (Eq, Show, Read, Generic, FromJSON, ToJSON )
          -- To/FromJSON are autogenerated JSON encode/decode instances

-- Auto-convert database rows into Person types for queries
instance FromRow Person where
    fromRow = Person <$> field <*> field <*> field <*> field <*> field

-- An expensive "insert" operation
-- Open a DB connection, create a table (maybe), insert the value, close the
-- connection
insertPersonIntoDB :: Person -> IO ()
insertPersonIntoDB (Person {..}) =
 do conn <- open "test.db"
    execute_ conn "CREATE TABLE IF NOT EXISTS people (name TEXT, surname TEXT, workPlace TEXT, accountBalance INTEGER, age INTEGER)"
    execute conn "INSERT INTO people (name,surname,workPlace,accountBalance,age) VALUES (?,?,?,?,?)" (name,surname,workPlace,accountBalance,age)
    close conn

-- A simple test to print out the whole table
printDB :: IO ()
printDB =
 do conn <- open "test.db"
    res <- query_ conn "SELECT * FROM people" :: IO [Person]
    putStrLn (unlines (map show res))
    close conn

-- Glue it all together by
-- 1. Make the json 2. parse the json 3. insert to DB 4. print entire DB
main :: IO ()
main =
  do let person_json = encode (Person "Tom" "MD" "Galois" (floor 1e9) 4)
     putStrLn $ "JSON: " ++ BC.unpack person_json
     case eitherDecode person_json of
        Left err     -> error err
        Right person -> insertPersonIntoDB person
     putStrLn "----- Database -----"
     printDB

结果如下:

% ghc so.hs
% ./so
JSON: {"accountBalance":1000000000,"age":4,"name":"Tom","workPlace":"Galois","surname":"MD"}
----- Database -----
Person {name = "Tom", surname = "MD", workPlace = "Galois", accountBalance = 1000000000, age = 4}

【讨论】:

  • 非常感谢托马斯。这正是我感兴趣的!
猜你喜欢
  • 1970-01-01
  • 2019-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-10
  • 2018-06-02
  • 2014-05-17
相关资源
最近更新 更多