如何在Notion中使用数据库数据和Node JS制作图表

1,175 阅读12分钟

流行的生产力工具Notion的功能非常全面,如果你渴望一些非原生的功能,你不一定要等待他们的团队包含一个实现,你可以建立自己的实现直接集成到他们的平台上

在撰写本文时,有一个这样的组件目前还不支持,那就是在Notion中从数据库数据中制作图表的能力。许多在线的无代码服务将提供他们自己的集成来提供图表,但如果你想知道如何使用Notion的APISDK,以及其他一些API来帮助渲染图表和托管图片,免费制作你自己的图表,那么请继续阅读,以发现完成这一任务的一种方法。

前提条件

要跟上本教程,你将需要以下条件:

  • 一个Notion账户--本教程假定是一个免费的个人账户
  • 在你的电脑上安装Node.JS

设置

为了设置并准备为这个项目编写一些JavaScript,将有一些设置说明以确保成功完成本教程。

第一步是对Notion进行设置,以便准备好访问和使用其API。第二步是创建账户并访问Imgur APIQuickChart,它们将被用来渲染图表和托管图片。最后一步是设置项目文件,并安装一切工作所需的依赖项。

在Notion中进行设置

本教程将假设读者知道如何在Notion中创建一个新的页面和一个表数据库。它还假定读者知道如何创建一个新的 集成

如果你不熟悉这个过程,请看本教程,看看设置数据库和创建集成所需的完整步骤,以及从哪里获得集成令牌。所有的集成设置步骤将与本教程相同,但不要将其命名为 "Demo",而是将集成命名为 "Charts"。这个来自Notion的专用指南也是一个很好的入门资源。

现在你已经了解了如何创建一个页面数据库和一个集成,下面看看这个项目的页面将如何结构化。

How the pages will be structured initially in Notion

创建两个新的页面,一个叫 "Chart",它将从数据库中的数据创建图表,另一个叫 "Database",它将只包含一个表数据库。

构建图表页面

在 "Chart "中,按以下顺序输入三个组件,然后按回车键。

  • Score: - 这只是文本。按回车键转到下一行。
  • /image - 按回车键,插入一个方框,作为图片的上传按钮。保持原样或上传一个占位符图片不会影响结果。
  • /heading3 - 按回车键后,输入 。突出显示此文本将使一个工具栏显示出来。点击工具栏上的Database链接按钮,打开一个文本框和下拉菜单。在下拉菜单中选择先前制作的数据库页面,或者在文本框中输入 "数据库 "来找到它。

Screenshot that shows how to hyperlink text from a Notion page to another page

这时,"图表 "页面就完成了,看起来像这样:

Screenshot of the completed Chart Notion page

之所以将数据库内联添加到这个页面会有问题,或者使用专用的/linktopage 命令来链接到数据库页面,是因为在撰写本文时,Notion API不支持这些组件的删除或添加。因此,超链接文本将是包含对图表所要提取的数据的参考的主要方式。

构建数据库页面

导航到你的数据库页面,输入"/",然后向下滚动到DATABASE部分。点击表视图,然后点击右侧边栏上的**+新数据库**按钮。一个新的数据库就会出现。

Default database in Notion when creating a new database from scratch

保持第一列为 "姓名",但将第二列从多选类型改为数字,并将其重新命名为 "分数"。填入以下字段,以便数据库有一些数据用于图表。

Completed Notion database needed for the tutorial

在这一点上,"图表 "和 "数据库 "页面已经可以使用了。点击页面右上方的三个点,向下滚动到连接。在弹出的 "添加连接"中,搜索并包括本教程一开始设置的 "图表 "这一集成名称。如果一开始没有设置,请按照之前的教程,了解如何创建一个。请确保在 "图表 "页和 "数据库 "页中共享这个集成,点击在文本框中输入名称时显示的集成名称。

Adding an integration to a notion page using the add connections menu

下一步是从你的 "图表 "页面获得页面ID,从你的数据库获得数据库ID。

抓住你的 "图表 "页面的URL,它将看起来像这样:https://www.notion.so/Chart-6a6d75d2d6334d3a8c397aca6e523cb7页面ID将是在Chart- 之后找到的代码。一旦你抓到了ID,它需要以8-4-4-4-12的字符长度模式出现,看起来像下面这样。xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

对于数据库ID,前往你的 "数据库 "页面,并通过点击下面的高亮按钮将其作为一个完整的页面打开。Database page with full page button highlighted

一旦它被打开,URL将看起来像这样。

https://www.notion.so/2294ec2a019c4b47b64c5af87b670df7?v=a0443a853c084c0a96cfdf9a2b36495f.数据库ID将是最后一个反斜杠和第一个问号之间的代码。

设置为使用Imgur和QuickChart API

本教程利用QuickChart来渲染图表,并利用Imgur来托管上述图表。由于未知的原因,Notion API不能将QuickChart的URL识别为图片,所以为了解决这个问题,图表将被上传到一个更容易识别的Imgur URL。

获取Imgur凭证

前往Imgur网站,创建一个免费账户。这个账户将保留你上传的所有图表图片,这些图片默认都是隐藏的,这意味着它们不会在网站上公开显示,但会通过URL随时访问。为此,要确保所有的图表信息尽可能的匿名化。

一旦你的账户设置完毕并准备就绪,继续 注册你的应用程序以使用Imgur的API并填写以下字段。

  • 应用程序名称下,输入 "图表"。
  • 授权类型下,选择 "带有回调URL的OAuth 2授权"。
  • 授权回调URL下,粘贴以下链接。https://www.getpostman.com/oauth2/callback.
  • 应用网站留空。
  • 电子邮件描述下,输入你自己的电子邮件和应用程序的描述,或者在这两个字段中输入一个句号。
  • 勾选reCAPTCHA框,然后点击底部的灰色提交按钮。

一旦提交,Imgur将把你重定向到一个新的页面,上面有你的代码,将用于我们对他们的API的请求,客户ID客户秘密

Acquiring credentials for Imgur

复制并保留这些值。本教程中使用的是客户ID,因为它是唯一需要上传图片的,但为了完整起见,也要保存客户秘密

使用QuickChart进行设置

使用QuickChart API的最大好处是,使用他们的服务不需要API密钥或凭证。为了便于使用,本教程采用了QuickChart SDK,将在下一节进行安装和初始化。

设置项目文件和安装依赖性

在你的电脑终端,浏览到一个你想存储项目文件的目录,并输入以下命令:

mkdir notion-charts
cd notion-charts

一旦进入空的notion-charts 目录中,初始化一个新的npm项目,并安装Notion SDKdotenv库(用于读取Notion和Imgur的私有证书)、QuickCharts SDKaxios,以便通过以下命令发送请求。

npm init -y
npm install @notionhq/client dotenv quickchart-js axios

一旦所有的依赖关系都安装好了,通过以下命令创建两个文件index.js 和*.env*两个文件,使用下面的命令。

touch index.js .env

打开*.env*文件,粘贴以下变量,将每个<PLACEHOLDER> ,替换为设置过程中收集到的相应数值。注意,NOTION_API_KEY 是创建 "图表 "集成时获得的集成令牌

NOTION_API_KEY=<PLACEHOLDER>
NOTION_DATABASE_ID=<PLACEHOLDER>
NOTION_PAGE_ID=<PLACEHOLDER>
IMGUR_CLIENT_ID=<PLACEHOLDER>
IMGUR_CLIENT_SECRET=<PLACEHOLDER>

保存*.env*文件,在你喜欢的代码编辑器或IDE中打开该项目。我在本教程中使用VSCode,到目前为止,我的文件结构是这样的。

Complete files in notion charts directory

打开package.json, 将突出显示的一行添加到”scripts” ,然后保存。

{
  "name": "notion-charts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@notionhq/client": "^2.1.1",
    "axios": "^0.27.2",
    "chart.js": "^3.9.1",
    "dotenv": "^16.0.1",
    "quickchart-js": "^3.1.0"
  }
}

一旦完成,最后一步是导入我们安装的所有依赖项,并设置一些全局变量,以存储必要的凭证。在你的编辑器中打开index.js,在空文件的顶部粘贴以下内容。

// Importing all necessary dependencies
const QuickChart = require('quickchart-js');
const dotenv = require('dotenv');
const { Client } = require('@notionhq/client');
const axios = require('axios');
dotenv.config();

// Creating global variables that store our API credentials and other necessary information
const notion = new Client({ auth: process.env.NOTION_API_KEY });
const databaseId = process.env.NOTION_DATABASE_ID;
const pageId = process.env.NOTION_PAGE_ID;
const clientId = process.env.IMGUR_CLIENT_ID;

保存index.js文件后,设置就完成了,该项目已经准备好了一些代码

使用数据库信息来创建一个图表

Notion SDK增加了对访问存储在其数据库中的信息的直接支持。在本节中,这些数据库信息被发送到QuickChartQuickChart会在其平台上渲染图表,并发回一个包含图片的URL。在写这篇文章的时候,Notion不支持通过他们的API直接上传图片,所以这个项目需要外部托管。

编写一个函数来查询Notion数据库并获得子块

第一个将被添加到index.js的函数将提供查询Notion数据库的方法。第二个函数将返回一个页面上所有子块的列表,并给出页面ID。

在全局变量定义的下面,粘贴以下两个函数。

// This function is used to access the data from a Notion database given the database ID
async function queryDatabase(databaseId) {
    try {
        const response = await notion.databases.query({
            database_id: databaseId,
          });  
        return response.results;
    } catch (error){
        console.log(error.body);
    }
}

// This function is used to access up to 50 child blocks per page given the page ID
async function getChildBlocks(pageId) {
    try {
        const response = await notion.blocks.children.list({
            block_id: pageId,
            page_size: 50,
          });
        return response.results;
    } catch (error){
        console.log(error.body);
    }
}

这两个函数使用Notion的API来访问数据库或页面中的信息。只要你的集成已经与 "数据库 "和 "图表 "页面共享,那么你在设置时复制的集成令牌将能够通过适当的databaseIdpageId

在Notion文档或之前链接的关于如何使用Notion数据库的帖子中阅读更多关于 getChildBlocks() 函数和 queryDatabse() 函数的工作原理。有了这两个函数,你现在可以在进一步的功能中使用它们。

使用QuickChart用Notion数据库数据创建图表

要用Notion数据库的数据创建图表并用QuickChart渲染,首先需要查询数据库,根据你的数据库模式解析数据(在这种情况下,数据库对每个条目只有两个值,即姓名分数),并将这些数据以数组的形式提供给QuickChart API调用。

getChildBlocks() 函数定义下面,粘贴以下内容。

// This function will access the data from the given database, generate a chart with QuickChart,
// and return the QuickChart URL containing the chart image 
async function getChart(databaseId, chartType) {

    const data = await queryDatabase(databaseId)
        .then(async results => {
            const dataPts = [];
            const labels = [];

            for(i = 0; i < results.length; i++) {
                const pageId = results[i].id;
                const nameId = results[i].properties.Name.id;
                const scoreId = results[i].properties.Score.id;

                try {
                    const nameVal = await notion.pages.properties.retrieve({ page_id: pageId, property_id: nameId });
                    const scoreVal = await notion.pages.properties.retrieve({ page_id: pageId, property_id: scoreId });  
                    labels.push(nameVal.results[0].title.text.content);
                    dataPts.push(scoreVal.number);

                } catch (error){
                    console.log(error.body);
                }
            }
            return {"Labels":labels, "Data Points":dataPts};
        });

    const myChart = new QuickChart();
    myChart.setConfig({
            type: chartType,
            data: { labels: data["Labels"], 
            datasets: [{ label: 'Scores', data: data["Data Points"] }] },
    })
    .setWidth(800)
    .setHeight(400)
    .setBackgroundColor('transparent');

    // the chart URL
    //console.log(myChart.getUrl());
    return myChart.getUrl();
}

突出显示的一行将打印图表的URL,我们可以通过取消该行的注释,然后直接在getChart() 函数的下面粘贴以下代码片段来测试。

getChart(databaseId, 'pie');

通过在项目目录中输入以下命令来运行这个程序。

npm run start

这将访问数据库信息,根据每个名字分数进行解析,将这些信息提供给QuickChart,然后打印生成的图表的URL。

Testing the getChart function

复制该链接在浏览器中查看,将显示一个代表Notion数据库数据的漂亮饼图。

Pie chart image with Notion database data

看看QuickChart的文档,看看所有不同类型的图表和设置,你可以用来定制它们。QuickChart的JavaScript客户端库也提供了大量的自定义选项。

在本教程中,我们将坚持使用饼图,但getChart() 函数将通过其第二个参数chartType ,产生任何支持的图表类型,并对某些类型进行一些必要的修改。

在继续前行之前,删除对getChart() 的调用,并随意注释回打印图表URL的console.log() 语句。

用新图表替换现有图表

本节将需要编写所需的函数,仅使用API调用将QuickChart图片上传到Imgur,然后使用Imgur链接来替换Notion "图表 "页面上的现有图片。

将QuickChart链接换成Imgur链接

如前所述,Notion不承认QuickChart链接是图片。为了让图片在页面上显示出来,它们必须由外部托管,所以我们也不能生成图表并上传。因此,解决这个问题的一个办法是简单地使用不同的服务,如Imgur,来托管QuickChart生成的图片。

getChart() 函数定义下面,粘贴以下swapLinks() 函数。

// This function will take the QuickChart link and upload it to Imgur and return the Imgur link
async function swapLinks(clientId, chartlink) {

    const imgurLink = await axios
        .post('https://api.imgur.com/3/image', chartlink, {
          headers: {
            Accept: "application/json",
            Authorization: `Client-ID ${clientId}`,
          },
        })
        .then(({data}) => {
          return data.data.link;
      });
    
    // console.log(imgurLink);
    return imgurLink;
}

为了测试这个函数,在swapLinks() 函数定义下面粘贴以下内容。

getChart(databaseId, 'pie').then(chartUrl => swapLinks(clientId, chartUrl));

swapLinks() 中取消了console.log(imgurLink); 语句,Imgur链接被打印到终端,可以粘贴到浏览器窗口中查看。

Printing the imgur link generated from uploading the QuickChart link

按照这个链接可以看出,图片已经成功上传了!

The image uploaded to Imgur successfully

删除对swapLinks() 的最后一次调用,然后进入下一节,了解如何用这些Imgur链接在Notion页面上原地替换图片。

用新的链接替换图表

在写这篇文章的时候,Notion API并不支持在页面上替换图片的功能,只支持删除 Block对象和追加 Child block对象。这意味着,为了改变图片,一个页面上的所有对象都需要按照它们在页面上出现的准确顺序被缓存在一个数组中。这个缓存中的图片链接需要被改变以反映更新的链接,然后所有的块需要被删除,只有这样才能将这个修改后的缓存追加为新的子块。

swapLinks() 函数的下面,粘贴下面的replaceCharts() 函数。

// Will search through the results array, get each blockId, and replace
// all image blocks with the imgUrls array argument in order
function replaceCharts(pageId, imgUrls) {

    getChildBlocks(pageId)
    .then(async results => {
        // Get locations and ID's for previous images
        const prevImages = [];
        const allBlockIds = [];
        const indexLocations = [];

        // Reconstruct the children array + gather all ID's
        const children = new Array(results.length).fill(0);

        for(i = 0; i < results.length; i++) {
            allBlockIds.push(results[i].id)

            // If block is an image, store it in prevImage cache and save index
            // If not, store the block as-is into children array
            if(results[i].type == 'image') {
                prevImages.push(results[i].id);
                indexLocations.push(i);
            } else {
                const dataType = results[i]['type'];
                children[i] = { [dataType] : results[i][dataType] };
            }
        }

        // Now add new images to children array
        for(i = 0; i < imgUrls.length; i++) {
            const img =           
            {
                "image" : {
                    "caption": [],
                    "type": "external",
                    "external": {
                        "url": imgUrls[i],
                    }
                },
            }
            const index = indexLocations.shift();
            children[index] = img;
        }
        
        // Go through all current blocks, delete, then append children
        for (i = 0; i < allBlockIds.length; i++) {            
            await notion.blocks.delete({
                block_id: allBlockIds[i],
            });
        }

        // Append children
        await notion.blocks.children.append({
            block_id: pageId,
            children: children,
        });
    });
}

由于replaceCharts() 支持多个图片链接,imgUrls 参数必须以数组形式传入。测试这个函数,在其定义下粘贴以下replaceCharts() 函数调用,将你的Imgur图片链接作为一个数组中的单个字符串元素。

replaceCharts(pageId, ['https://i.imgur.com/XwU6DJt.png']);

在终端中用npm run start 来运行这段代码,看你的Notion "图表 "页面在你眼前发生变化。

删除对replaceCharts() 的调用,然后进入本教程的最后一步,将其全部整合。

刷新Notion页面

现在你已经完成了从Notion数据库数据创建图表和替换Notion页面上现有图像所需的所有部分,最后一步是创建一个驱动函数,该函数将调用每个函数并将信息从一个函数传递到另一个函数。

replaceCharts() 函数定义之后,粘贴本教程的最后一个函数,refreshPage() 以下。

// The main driver of the program
async function refreshPage(databaseId, pageId, clientId, chartType) {

    // 1 - Get the QuickChart link from getChart()
    const quickChart = await getChart(databaseId, chartType);
  
    // 2 - Swap links from QuickChart to Imgur
    const imgurUrl = await swapLinks(clientId, quickChart);

    // 3 - Replace images on Notion page
    replaceCharts(pageId, [imgurUrl]);
}

refreshPage() 函数定义之后粘贴以下调用,以测试这个函数。

refreshPage(databaseId, pageId, clientId, 'pie');

随意将chartType 改为bar ,而不是pie ,以看到一个新的图表,或者向你的数据库添加额外的数据,以观察一切变化

现在你可以从Notion数据库的数据中生成图表了!

通过利用多个API和平台的力量,你能够为你的Notion页面提供非本地的功能。可视化是一个强大的工具,可以在不查看原始数据的情况下快速了解概况,现在你有了制作自己的手段,可能性是无限的

如果你在市场上有更多的项目想法,我强烈建议你浏览Twilio的博客以获得一些灵感。在那之前,请继续建设,并祝你编码愉快!