{"id":822,"date":"2025-02-07T04:10:02","date_gmt":"2025-02-06T20:10:02","guid":{"rendered":"https:\/\/yanghaixiong.com\/?p=822"},"modified":"2025-02-07T04:10:02","modified_gmt":"2025-02-06T20:10:02","slug":"obsidian%e6%8f%92%e4%bb%b6dataview-%e5%ae%9e%e7%94%a8%e6%a1%88%e4%be%8b%e8%ae%b2%e8%a7%a3%ef%bc%88%e9%ab%98%e7%ba%a7%e7%af%87%ef%bc%89%ef%bc%88%e5%8d%81%e5%9b%9b%ef%bc%89","status":"publish","type":"post","link":"https:\/\/yanghaixiong.com\/blog\/skills\/822\/","title":{"rendered":"Obsidian\u63d2\u4ef6Dataview \u2014\u2014 \u5b9e\u7528\u6848\u4f8b\u8bb2\u89e3\uff08\u9ad8\u7ea7\u7bc7\uff09\uff08\u5341\u56db\uff09"},"content":{"rendered":"
\n [!quote] \u80cc\u666f
\n \u4e3b\u8981\u68b3\u7406\u4e86 Dataview \u793a\u4f8b\u5e93\u00a0Dataview Example Valut<\/strong>\u00a0\u4e2d\u7684\u4e00\u4e9b\u6848\u4f8b\n<\/p><\/blockquote>\n\u4e09\u3001\u9ad8\u7ea7\u7bc7\uff1aDataview \u9ad8\u7ea7\u6280\u5de7\u4e0e\u63a2\u7d22<\/h2>\n
\u9ad8\u7ea7\u7bc7\u7684\u5185\u5bb9\u4e3b\u8981\u662f\u4e00\u4e9b\u4e0d\u5e38\u7528\uff0c\u4f46\u662f\u5b9e\u7528\uff0c\u9700\u8981\u66f4\u591a\u7684\u4ee3\u7801\u7684\u5185\u5bb9\uff0c\u6216\u8005\u9700\u8981\u7ed3\u5408\u7b2c\u4e09\u65b9\u63d2\u4ef6\u7684\u5185\u5bb9\u3002<\/p>\n
1. \u8868\u683c\u5217\u6c42\u548c<\/h3>\n
\u5728\u7535\u5b50\u8868\u683c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u5217\u6570\u636e\u8fdb\u884c\u8fd0\u7b97\uff0c\u5982\u6c42\u548c\u3001\u672a\u5e73\u5747\u503c\u7b49\u3002\u4e0b\u9762\u6211\u4eec\u6765\u770b\u4e00\u4e0b\u5982\u4f55\u5728 Dataview \u67e5\u8be2\u7684\u7ed3\u679c\u4e2d\u5b9e\u73b0\u5bf9\u5217\u6570\u636e\u7684\u6c42\u548c\u3002<\/p>\n
const query = `TABLE praying, training, situps, steps\nFROM \"10 Example Data\/dailys\"\nWHERE file.day.month = 2`\n\nconst nameOfTotalRow = \"Sums\";\n\nlet DQL = await dv.tryQuery(query);\nconst sums = [nameOfTotalRow];\n\n\/\/ \u5982\u679c\u5728 DQL \u67e5\u8be2\u8bed\u53e5\u4e2d\u6dfb\u52a0\u4e86 `WITHOUT ID`\uff0c\u8fd9\u91cc\u5c31\u9700\u8981\u6539\u6210\u4ece `0` \u5f00\u59cb\u904d\u5386\nfor (let i = 1; i < DQL.headers.length; i++) {\n let sum = 0;\n const dataType = getDatatypeOfColumn(i, DQL.values)\n\n \/\/ \u53ea\u6709\u6570\u5b57\u548c\u6301\u7eed\u65f6\u95f4\u7684\u6570\u636e\u7c7b\u578b\u624d\u4f1a\u88ab\u8ba1\u7b97\n if (![\"number\", \"duration\"].includes(dataType)) {\n sums.push(\"\")\n continue;\n }\n\n \/\/ \u8ba1\u7b97\u6bcf\u4e00\u5217\u7684\u603b\u548c\n for (let k = 0; k < DQL.values.length; k++) {\n \/\/ \u884c `k`, \u5217 `i` \u7684\u503c\n let currentValue = DQL.values[k][i];\n if (currentValue) sum += currentValue \n }\n if (!sum) sum = \"\"\n sums.push(dataType === \"duration\" ? dv.luxon.Duration.fromMillis(sum) : sum);\n}\n\nfunction getDatatypeOfColumn(columnNo, values) {\n let i = 0;\n let datatype;\n while (i < DQL.values[0].length && (!datatype || datatype === \"null\")) {\n datatype = dv.func.typeof(DQL.values[i][columnNo])\n i++;\n }\n return datatype;\n}\n\n\/\/ \u6dfb\u52a0\u5206\u9694\u7ebf\nlet hrArray = Array(DQL.headers.length).fill('<hr style=\"padding:0; margin:0 -10px;\">');\nDQL.values.push(hrArray)\nDQL.values.push(sums)\n\ndv.table(DQL.headers, DQL.values)\n<\/code><\/pre>\n
\u7ed3\u679c\uff1a
\n<\/p>\n
2. \u5728\u6587\u6863\u4e2d\u641c\u7d22\u6587\u5b57<\/h3>\n
\u8981\u5728\u6587\u6863\u4e2d\u641c\u7d22\u6307\u5b9a\u7684\u5355\u8bcd\uff0c\u6211\u4eec\u9996\u5148\u9700\u8981\u5c06\u6587\u4ef6\u8bfb\u5230\u5185\u5bb9\u4e2d\uff0c\u53ef\u4f7f\u7528\u00a0
dv.io.load()<\/code>\u00a0\u65b9\u6cd5\uff0c\u7136\u540e\u518d\u901a\u8fc7\u6b63\u5219\u53bb\u5339\u914d\u6587\u672c\u3002<\/p>\n
const word = \"but\"\n\nconst regex = new RegExp(\"(\\\\S+\\\\s?){0,2}(\\\\b\"+word+\"\\\\b)(\\\\s\\\\S+){0,2}\", \"gi\")\nconst pages = await Promise.all(\n dv.pages('\"30 Dataview Resources\"')\n .map(async (page) => {\n const content = await dv.io.load(page.file.path);\n const matches = content.match(regex);\n return {\n link: page.file.link,\n count: ( matches || []).length,\n matches\n };\n })\n)\n\ndv.table(\n [\"Note\", \"Count\", `Matches for \"${word}\"`],\n pages\n .filter(p => p.count)\n .sort((a, b) => b.count - a.count)\n .map(p => [p.link, p.count, p.matches]) \n );\n<\/code><\/pre>\n
\u7ed3\u679c\uff1a
\n
\n\u4e0a\u9762\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u4e2d\\b<\/code> \u7528\u4e8e\u5339\u914d\u5355\u8bcd\u8fb9\u754c\uff08\u82f1\u6587\u53e5\u5b50\u5355\u8bcd\u4e4b\u95f4\u4ee5\u7a7a\u683c\u5206\u9694\uff09\uff0c\u7136\u540e\u6700\u5de6\u8fb9\u7684
(\\\\S+\\\\s?){0,2}<\/code> \u548c\u53f3\u8fb9\u7684
(\\\\s\\\\S+){0,2}<\/code> \u7528\u4e8e\u5339\u914d\u76ee\u6807\u5355\u8bcd\u524d\u540e\u7684\u4e24\u4e2a\u76f8\u90bb\u5355\u8bcd\u3002\u57fa\u4e2d
+<\/code> \u7b26\u8868\u793a\u5339\u914d 1 \u6b21\u6216\u591a\u6b21\uff0c
?<\/code> \u8868\u793a\u5339\u914d 0 \u6b21\u6216\u591a\u6b21\uff0c
\\s<\/code> \u8868\u793a\u5339\u914d\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\uff08\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\u3001\u6362\u9875\u7b26\u548c\u6362\u884c\u7b26)\uff0c
\\S<\/code> \u8868\u793a\u5339\u914d\u4e00\u4e2a\u975e\u7a7a\u767d\u7b26\u3002
dv.io.load()<\/code> \u65b9\u6cd5\u7528\u4e8e\u5c06\u6587\u4ef6\u52a0\u8f7d\u5230\u5185\u5b58\u4e2d\u3002<\/p>\n
3. \u4f7f\u7528\u9009\u9879\u5361\u5207\u6362\u6570\u636e<\/h3>\n
\u5728\u67e5\u8be2\u6570\u636e\u65f6\uff0c\u6709\u7684\u6570\u636e\u4e0d\u540c\u7684\u72b6\u6001\u4f1a\u6709\u4e0d\u540c\u7684\u7ed3\u679c\uff0c\u6211\u4eec\u53ef\u4ee5\u6309\u72b6\u6001\u6765\u8fdb\u884c\u6761\u4ef6\u663e\u793a\u3002\u5c06\u72b6\u6001\u4f5c\u4e3a\u9009\u9879\u5361\uff0c\u800c\u5176\u5173\u8054\u7684\u5185\u5bb9\u4f5c\u4e3a\u9009\u9879\u5361\u5185\u5bb9\u3002<\/p>\n
const createButton = name => {\n const btn = dv.el('button', name)\n btn.addEventListener('click', () => {\n event.preventDefault()\n removeTable()\n renderTable(name)\n })\n\n return btn\n}\n\nconst buttons = ['Watching', 'Going to watch', 'Watched all', 'Stopped watching']\n\nconst renderTable = name => {\n const pages = dv.pages('\"10 Example Data\/shows\"').where(p => p.status === name)\n dv.header(2, name)\n dv.table(\n ['Title', 'Rating', 'Runtime', 'Seasons', 'Episodes'],\n pages.map(p => {\n let watchedEp = 0\n const totalEp = p.episodes\n\n p.file.tasks.forEach(t => {\n if (t.checked) {\n watchedEp++\n }\n })\n\n return [p.file.link, p.rating, p.runtime, p.seasons, `${watchedEp}\/${totalEp}`]\n })\n )\n}\n\nconst removeTable = () => {\n this.container.lastChild.remove()\n this.container.lastChild.remove()\n}\n\nbuttons.forEach(button => createButton(button))\n\nrenderTable('Watching')\n<\/code><\/pre>\n
\u7ed3\u679c\uff1a
\n
\n\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u00a0dv.el()<\/code>\u00a0\u6765\u521b\u5efa\u4e86\u6309\u94ae\u5e76\u6dfb\u52a0\u4e86\u4e8b\u4ef6\u5904\u7406\u903b\u8f91\u3002\u5728\u9009\u9879\u5361\u88ab\u9009\u4e2d\u65f6\uff0c\u6839\u636e\u9009\u9879\u5361\u540d\u53bb\u8fc7\u6ee4\u67e5\u8be2\u7ed3\u679c\uff0c\u5e76\u5c06\u4e0a\u4e00\u6b21\u6e32\u67d3\u7684 HTML \u8282\u70b9\u79fb\u9664\u6389\u3002<\/p>\n
\u8fdb\u4e00\u6b65\uff0c\u6211\u4eec\u8fd8\u53ef\u4ee5\u5b9e\u73b0\u540c\u4e00\u4efd\u6570\u636e\u7ed3\u679c\u4ee5\u4e0d\u540c\u7684\u65b9\u5f0f\u6e32\u67d3\uff1a<\/p>\n
const views = ['Table', 'List', 'Tasks']\n\nconst changeView = viewName => {\n removeView()\n\n if (viewName === 'Table') {\n dv.header(2, 'Some table')\n dv.table(['File', 'Day'], dv.pages('\"10 Example Data\/dailys\"').limit(7).map(p => [p.file.link, p.day]))\n }\n\n if (viewName == 'List') {\n dv.list(dv.pages('\"10 Example Data\/dailys\"').limit(7).file.name)\n }\n\n if (viewName == 'Tasks') {\n dv.taskList(dv.page(\"10 Example Data\/projects\/project_2\").file.tasks)\n }\n}\n\nconst createButtons = () => {\n const buttonContainer = dv.el('div', '', {cls: 'tabButtons'})\n views.forEach(view => {\n const button = dv.el('button', view)\n\n button.addEventListener('click', event => {\n event.preventDefault()\n changeView(view)\n })\n\n buttonContainer.append(button)\n })\n}\n\nconst removeView = () => {\n Array.from(this.container.children).forEach(el => {\n if (!el.classList.contains('tabButtons')) {\n el.remove()\n }\n })\n}\n\ncreateButtons()\n<\/code><\/pre>\n
4. \u4f7f\u7528\u4e0d\u540c\u7684\u8868\u60c5\u7b26\u6765\u663e\u793a\u65f6\u95f4\u7f00<\/h3>\n
\u8fd9\u4e2a\u6848\u4f8b\u6211\u4eec\u67e5\u8be2\u4efb\u52a1\u8ba1\u5212\u6570\u636e\uff0c\u6765\u83b7\u53d6\u672a\u5b8c\u6210\u7684\u4efb\u52a1\u8ddd\u79bb\u73b0\u5728\u8fc7\u53bb\u4e86\u591a\u957f\u65f6\u95f4\uff0c\u5e76\u5bf9\u5176\u6309\u65f6\u95f4\u957f\u5ea6\u81ea\u5b9a\u4e49\u4e0d\u540c\u7684\u8868\u60c5\u7b26\u6765\u663e\u793a\u5f97\u5206\u3002<\/p>\n
\n
- \u5982\u679c\u6708\u6570\u8d85\u8fc76\u4e2a\u6708\uff0c\u5219\u6dfb\u52a0 “\ud83e\udd73” \u8868\u60c5\u7b26\u53f7\u3002<\/li>\n
- \u5982\u679c\u5269\u4f59\u7684\u6708\u6570\uff08\u5728\u8d85\u8fc76\u4e2a\u6708\u540e\uff09\u8d85\u8fc73\u4e2a\u6708\uff0c\u5219\u6dfb\u52a0 “\ud83c\udf89” \u8868\u60c5\u7b26\u53f7\u3002<\/li>\n
- \u5982\u679c\u5269\u4f59\u7684\u6708\u6570\uff08\u5728\u8d85\u8fc79\u4e2a\u6708\u540e\uff09\u4ecd\u7136\u6709\u5269\u4f59\uff0c\u5219\u6dfb\u52a0 “\ud83c\udf81” \u8868\u60c5\u7b26\u53f7\u3002<\/li>\n<\/ul>\n
const projects = dv.pages('\"10 Example Data\/projects\"')\n .where(p => p.status !== undefined && p.status !== \"finished\")\n .mutate(p => {\n p.age = p.started && p.started instanceof dv.luxon.DateTime ? dv.luxon.Duration.fromMillis(Date.now() - p.started.toMillis()) : null\n p.emojiAgeScore = getEmojiScore(p)\n })\n\ndv.table([\"Score\", \"Project\", \"Started\", \"Age\"], projects.map(p => [p.emojiAgeScore, p.file.link, p.started, p.age ? p.age.toFormat(\"y'\u5e74' M'\u4e2a\u6708' w'\u5468'\") : 'N\/A']))\n\nfunction getEmojiScore(p) {\n const age = p.age.shiftTo('months').toObject()\n let score = \"\"\n\n score += addEmojis(\"\ud83e\udd73\", age.months \/ 6)\n score += addEmojis(\"\ud83c\udf89\", (age.months % 6) \/ 3)\n score += addEmojis(\"\ud83c\udf81\", age.months % 6 % 3)\n\n return score\n}\n\nfunction addEmojis(emoji, max) {\n let emojis = \"\"\n for (let i = 0; i < Math.floor(max); i++) emojis += emoji\n return emojis\n}\n<\/code><\/pre>\n
\u7ed3\u679c\uff1a
\n
\n\u4ee3\u7801\u4e2d\u00a0shiftTo('months').toObject()<\/code>\u00a0\u51fd\u6570\u7528\u4e8e\u5c06\u65f6\u95f4\u7f00\u8f6c\u6362\u6210\u7c7b\u4f3c\uff1a
xx\u4e2a\u6708<\/code>\u00a0\u7684\u5f62\u5f0f\u3002<\/p>\n
\u5173\u4e8e Luxon \u7684\u4f7f\u7528\u53ef\u4ee5\u9605\u8bfb\u7cfb\u5217\u4e2d\u7684 Luxon \u7ae0\u8282\u3002<\/p>\n
5. \u5c06\u6570\u636e\u6e32\u67d3\u6210\u65e5\u5386<\/h3>\n
\u4e0b\u9762\u8fd9\u4e2a\u6848\u4f8b\u53ef\u4ee5\u597d\u597d\u7814\u7a76\u4e00\u4e0b\u5982\u4f55\u8fd0\u7528 Luxon \u586b\u5145\u6bcf\u5929\u7684\u6570\u636e\u548c\u6784\u9020 HTML \u7ed3\u6784\u3002<\/p>\n
const values = dv.pages('\"10 Example Data\/dailys\"').where(p => p.wellbeing?.mood)\nconst year = 2022\nconst color = \"green\"\nconst emptyColor = \"#e4e4e4\"\nconst dt = dv.luxon.DateTime\n\n\/\/ \u521b\u5efa\u65e5\u5386\u6570\u636e\nlet date = dt.utc(year)\nconst calendar = []\nS\nfor (let i = 1; i <= 12; i++) {\n calendar[i] = []\n}\n\n\/\/ \u586b\u5145\u65e5\u5386\u6570\u636e\nwhile (date.year === year) {\n calendar[date.month].push(getDayEl(date, determineColor(date)))\n\n date = addOneDay(date);\n}\n\n\/\/ \u6e32\u67d3\u65e5\u5386\ncalendar.forEach((month, i) => {\n const monthEl = `<span style=\"display:inline-block;width:30px;font-size:small\">${dt.utc(year, i).monthShort}<\/span>`\n dv.el(\"div\", monthEl + month.reduce((acc, cur) => `${acc} ${cur}`, \"\"))\n})\n\nfunction addOneDay(date) {\n return dt.fromMillis(date + dv.duration(\"1d\"))\n}\n\nfunction getDayEl(date, color) {\n const sizeOfDays = \"12px\"\n return `<span style=\"width:${sizeOfDays};height:${sizeOfDays};border-radius:2px;background-color:${color};display:inline-block;font-size:4pt;\" title=\"${date.toFormat('yyyy-MM-dd')}\"><\/span>`\n}\n\nfunction determineColor(date) {\n const page = values.find(p => p.file.day.startOf('day').equals(date.startOf('day')));\n if (!page) return emptyColor;\n\n\n let opacity = (page.wellbeing.mood \/ 4) ;\n return `rgba(177, 200, 51, ${opacity})`;\n\n}\n<\/code><\/pre>\n
\u7ed3\u679c\uff1a
\n<\/p>\n
\u8fdb\u4e00\u6b65\u9605\u8bfb\uff1aRender a year overview for your data – Dataview Example Vault (s-blu.github.io)<\/a><\/p>\n
6. \u4f7f\u7528 Chart. Js \u6e32\u67d3\u56fe\u8868<\/h3>\n