# Datascript入门

## datascript有什么用？

## 在Logseq使用

### 什么是匹配？

datascript是一种`匹配`查询的语言,我们从最简单的语句开始，一步一步提高直到学会\`datascript\`。

什么是匹配呢？我们设想`Logseq`的数据库是长这样的

| E-id | Attribute      | Value |
| ---- | -------------- | ----- |
| 50   | :block/parent  | 49    |
| 50   | :block/content | 大学数学  |
| 51   | :block/parent  | 50    |
| 51   | :block/content | 微积分   |
| 52   | :block/parent  | 50    |
| 52   | :block/content | 线代    |
| 53   | :block/parent  | 49    |
| 53   | :block/content | 大学英语  |

这个表在`Logseq`中看起来是什么样的呢？是这样。微积分和线代的父节点是大学数学。大学数学和大学英语同层级。

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2Fgit-blob-f2856067295ab7e1a28e9491b41c037b439a4cbd%2F28.png?alt=media)

我们构造这个命令

```
[:find ?e 
    :where
     [?e :block/parent 50]]
```

ps：这是`datascript`的语法，在`logseq`中使用还需要加上特定的语法，例:

```
#+BEGIN_QUERY
{:title "找到父节点为50的节点"
    :query [:find ?e 
    :where
     [?e :block/parent 50]]
}
#+END_QUERY
```

`[?e :block/parent 50]`意思就是匹配所有`block`中`parent`是`50`的节点。在我们这里表里面，结果有两个，分别是`51`和`52`。那么这个`?e`就是`变量`，它的值来源于与`:block/parent 50`相匹配行的`e-id`，现在的`?e`的值是`51`、`52`。

![我logseq上微积分是72，线代是73](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2F3LuYU44PWQrI885x9giJ%2F29.png?alt=media\&token=9206ccb8-6a86-4750-9a9d-b2a98eb3f5a8)我的logseq中微积分是72， 线代是73。

`(pull 变量名 [*])`这个`方法`的作用是把`变量名`所对应的`block`显示出来：

```
[:find (pull ?e [*])
    :where
     [?e :block/parent 50]]
```

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2FAiEGcID2TBRTymXKyZi6%2F30.png?alt=media\&token=7e8b5229-b6fa-483d-be21-dd0d8cc20f8c)

###

### 多个匹配条件

还可能通过多个匹配语句去选择我们想要的`block`。

现在我们假设我们有一个这样的`logseq`库。

| E-id | Attribute      | Value  |
| ---- | -------------- | ------ |
| 50   | :block/marker  | TODO   |
| 50   | :block/content | 学习英语   |
| 51   | :block/marker  | TODO   |
| 51   | :block/content | 学习数学   |
| 52   | :block/marker  | DONE   |
| 52   | :block/content | 学习语文   |
| 53   | :block/parent  | 49     |
| 53   | :block/content | 今天天气真好 |

看起来像这样

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2Fgit-blob-a8000e5b46889fa14ae692e0d5e30f7e8f0dd90c%2F31.png?alt=media)

我们构造一个筛选出目前还是`TODO`的`任务`的条件语句。

```
 [:find (pull ?e [*]) 
    :where
     [?e :block/marker ?m]
     [(contains? #{"TODO"} ?m)]]
```

我们来看看这两个条件语句是怎么起作用的。

当匹配条件一`[?e :block/marker ?m]`执行时，能与`:block/marker`相匹配的行有三个。 `?e`的值有三个`50`、`51`、`52` 。同时`?m`的值有`TODO`和`DONE`两个。

我们用第二个匹配条件`[(contains? #{"TODO"} ?m)]`，要求这个`?m`是在`#{"TODO"}`其中。所以`?m`是`DONE`的`52`就被排除了。现在`?e`只有`50`和`51`。

我们用`(pull ?e [*])`把`E-ID`为`50`和`51`的`block`显示出来：

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2Ftu2hE77E43GUv5OAhsTV%2F32.png?alt=media\&token=4354c4d2-f9b7-4933-b275-6746d68306db)

## 统计满足条件的`block`有多少

如果我们想通知一共有多少个`TODO`，而不是把他们列出来，我们应该使用 `(count 变量名)`去替换`(pull )`。

例：

```
 [:find (count ?e) 
    :where
     [?e :block/marker ?m]
     [(contains? #{"TODO"} ?m)]]
```

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2F74jWEDFP2JsMVTAdgOqy%2F33.png?alt=media\&token=62872b65-b872-42b6-b86a-bb25e4beda4e)

> note 如果想在console中执行datascript可以使用

```javascript
logseq.api.datascript_query(`
     [:find (pull ?e [*])
    :where
     [?e :block/marker ?m]
     [(contains? #{"TODO"} ?m)]]
`)
```

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2Fgit-blob-7a2a40ddbbc7ac56cbe4332b822b726639957a72%2F45.png?alt=media)

## 更多限制条件

在`logseq`中我们还可以使用更多的限制条件去筛选`block`，比如`日期`等等。

在`:input [:today :today]`这两个参数传给`?start`和`?end`两个变量。然后 `[?p :page/journal-day ?d]`则把日期赋予`?d`变量。

最后再把`?d`与`?start`和`?end`进去对比。

```
#+BEGIN_QUERY
{:title "找出今天的TODO任务数"
    :query  [:find (count ?e) 
    :in  $ ?start ?end
    :where
     [?e :block/marker ?m]
     [(contains? #{"TODO"} ?m)]
     [?p :page/journal-day ?d]
     [(>= ?d ?start)]
     [(<= ?d ?end)]]
    :inputs [:today :today]
}
#+END_QUERY
```

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2FtoJ8z31jAIAWH8651UqI%2F35.png?alt=media\&token=cbb4ad10-9746-464a-9cde-393e335748f1)

可以传入`:inputs`日期的值非常丰富可以自由组合，比如`:today`、`:7d`、`:56d`、`:7d-after`等等。

## 在`Logseq`插件中使用

`logseq`提供了`logseq.DB.datascriptQuery`去执行`datascript`语句。

比如当我们执行

```typescript
logseq.DB.datascriptQuery(`
     [:find (pull ?e [*]) 
    :where
     [?e :block/marker ?m]
     [(contains? #{"TODO"} ?m)]]
`)
```

我们尝试执行这个命令并`console.log`出来看看：

![](https://1814684483-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3IBeFiGUBD9MhOIooBXj%2Fuploads%2FS9gfktkQxPwon9idxDXc%2F34.png?alt=media\&token=5a8ce0c5-fc38-4c29-8a20-871e5bbadb3e)

### 在插件中使用条件限制

在开发中我们只为api提供`:query`而没有`:inputs` 。我们应该如何限制查询条件呢？

其实在插件中限制条件还可以更加的灵活与多样。因为可以使用js去往`[:find ]`中动态的使用的变量。不仅是如`[(>= ?d 日期)]`还可以在`(contains? )`中对block内容进行匹配。

只要我们了解相应的格式就行。如日期格式应该满足`yyyyMMdd`，如果`[(>= ?d 20220218)]`

## Logseq block自带的属性

| :Namespace/Attribute | 可能的值\|示例                      |
| -------------------- | ----------------------------- |
| :block/uuid          |                               |
| :block/parent        | 50                            |
| :block/left          |                               |
| :block/collapsed?    |                               |
| :block/format        |                               |
| :block/refs          |                               |
| :block/\_refs        |                               |
| :block/path-refs     |                               |
| :block/tags          |                               |
| :block/content       |                               |
| :block/marker        | "DONE"、"TODO"、 "NOW" 、"LATER" |
| :block/priority      |                               |
| :block/properties    |                               |
| :block/pre-block?    |                               |
| :block/scheduled     |                               |
| :block/deadline      |                               |
| :block/repeated?     |                               |
| :block/created-at    | 1644037172307                 |
| :block/updated-at    | 1644037172307                 |
| :block/file          |                               |
| :block/heading-level |                               |
