What are the limitations to using LogSeq properties to make a lightweight queryable graph database of pages?

Say I have a “lightweight relational database” in the form of a spreadsheet with a list of my favorite coffee shops (e.g. XLSX / CSV):

Name         Address       Serves Food
Perk Café    123 Main St.  Yes
Daily Joe    10 Broadway   No

I could alternately make two LogSeq pages (or blocks)

- Perk Cafe
type:: Coffee Shop
address:: 123 Main St.
serves_food:: Yes

- Daily Joe
type:: Coffee Shop
address:: 10 Broadway
serves_food:: No

Then if I query {{query (property type "Coffee Shop") }} I get a table back:

block type address serves-food
Daily Joe Coffee Shop 10 Broadway No
Perk Café Coffee Shop 123 Main St. Yes

Very cool, especially because in LogSeq one of course gets all the rest of the linking features of all my visits to / thoughts about Daily Joe, etc. etc. And, one can of course construct more complex queries.

Now say I collect 100 coffee shops.

Then say I realize that “address” isn’t really the right property key name because this could refer to web address or street address. So I want to change it to street_address.

In the “relational DB,” I just change the column name from address to street_address. As I understand it—which is not much—“real” graph databases also provide options to refactor a schema to address this situation.

What would I do in LogSeq, short of manually changing every one of the 100 entries? Is there just no efficient way to iterate one’s mental model of such data without manually redoing everything? (I would note that simply find-and-replace every “address” with “street_address” risks contaminating a bunch of normal references to the word “address” outside of the targeted entries.) I worry about this because it seems one of the whole mindsets of LogSeq as opposed to a relational DB is to build-bottom-up-as-you-go, rather than having to design-top-down-once-and-for-all. Am I missing a solution to this challenge?

More generally, are there other normal tasks one might typically complete with a database that become impractical if one instead uses LogSeq as a “lightweight graph database” in this manner?


Logseq is just text, so you can just do a find/replace on a 10000 items if you want, it won’t matter

Relational databases combine separate tables and use one table to find items from another, that might be rather complicated (although not impossible) in Logseq.

But a 100 coffee shops is, to use the technical term, peanuts: no problem at all.

Hi Alex_QWxleA,

Thanks for your thought. But as I wrote a find-and-replace will replace all text, including items that aren’t properties as well (or are unrelated properties in other files), and aren’t meant to be changed. So unless I’m missing something, it’s not a workable solution.


You would find-replace using a regex: ^address::street_address::

With plain text, as long as things have some logic, you can convert virtually anything: first with a normal find-replace, then regular expressions, then with a script like python, perl or javascript.

Still, Logseq is no database.

1 Like

Do you know a way to structure such a regex to filter / apply only to properties where there exist other properties of certain values? E.g.

 IF type==Coffee Shop THEN ^address:: --> street_address:

You would do something like this: regex101: build, test, and debug regex

Very cool. Thank you.

My broader concern remains—but this is a very neat intermediate solution as well as food for thought. And I appreciate your detailed problem-solving!

Posting this here for posterity…updated to match across blocks with properties not in consecutive order etc.

Matches: (type:: Coffee Shop)([\S\s]*?)(address::)(.*)
and substitutes: $1$2street_address::$4