> This sort of "concat" operation is a bad idea, because it is prone to 
> collisions...
 
Those were just examples to discuss a point. You can find similar types of 
concatenations in multiple guides
written for setting up postfix with a mysql backend. For example refer to 
'virtual_alias_domains.cf'
mentioned in arch linux's wiki page:
https://wiki.archlinux.org/title/Virtual_user_mail_system_with_Postfix,_Dovecot_and_Roundcube

I was just trying to understand if these type operations (concat, etc.) need to 
be supported in the
projection. Am I correct in understanding they are not?

> You're working too hard. This sort of thing just encourages bad
> design choices. Just implement "result_attribute" (typically just
> one), and "result_format" (ala LDAP) to pick this apart and inject
> it into some template if need be. Then combine multiple results
> (if need be) by separating with commas.

If the result_attribute + result_format design is the best practice, I'm all 
for that.
need to go look at the result_format and understand how to use it with mongo..

>> which would return:
>> maadani,ha...@dexo.tech/,dukhovni,vik...@postfix.org/
> 
> which makes no sense.
 
This is honestly confusing to me. This was meant to show we are printing 
multiple multi-valued
results as one comma separated string. When you say this makes no sense, are 
you referring to this
result not being useful to postfix because of multiple mail-paths in it? or the 
comma separated string part!?

> You do have to decide how mailing lists are modeled in MongoDB. Are
> they one row per member? Is it a list of "_id" values? Or a list of
> email addresses? If the former, how does list expansion work? Can
> MongoDB do joins as well as projections? ...

I imagine each list as a JSON object with an array of addresses inside of it. 
Something like:
{ "createdAt": ISODate("<some date>"), "active": 1, "addresses": [ 
"ha...@dexo.tech",
"vik...@postfix.org" ] }
 
Would that work?

MongoDB supports joins, but through "aggregation pipelines":
https://www.mongodb.com/docs/manual/aggregation

here, we are using 'mongoc_collection_find_with_opts' which runs a 'find' 
operation. If support for
joins are necessary, we should switch to 'mongoc_database_aggregate' and 
require 'filter' to be in the 
pipeline format:
http://mongoc.org/libmongoc/current/mongoc_database_aggregate.html


One more question, what's the policy regarding multiple databases? the way that 
the module is now, it
supports multiple collections (tables) in only one database. Should I put any 
effort in supporting multiple?
For example, if mailboxes are in cluster 1 and mail lists in cluster 2 
(separate URIs basically)?

Regards
Hamid Maadani

> June 21, 2022 6:29 PM, "Viktor Dukhovni" <postfix-us...@dukhovni.org> wrote:
> 
>> On Tue, Jun 21, 2022 at 07:26:53PM +0000, Hamid Maadani wrote:
>> 
>>> Want to discuss the 'result_attribute' before I go ahead with the 
>>> implementation though.
>>> It is kind of the same story as with 'filter' and 'search_key' attributes.
>> 
>> Not exactly, there are enough differences to warrant specific treatment.
>> 
>>> If we are to return multiple fields, each of which might need a custom
>>> projection.
>> 
>> Whatever the returned fields are, it only makes sense to combine values
>> of the same semantic "type". Postfix dictionary lookups return either a
>> single value or a list of comma-separated values with the list eleemnts
>> interpreted in a uniform way.
>> 
>> Therefore, in the typical case where the result attribute are returned
>> "as-is", the "projection" is trivial (identity function) and the values
>> (if more than one) are returned comma-separated.
>> 
>>> So, We would need to have multiple result_attributes, and each one is
>>> either set to '1' (matching exact field in the document),
>>> or an optional JSON document for projection.
>> 
>> No. The "result_attribute" list is a list of attributes whose values
>> are either used as-is or perhaps (in harmony with e.g. the LDAP table)
>> are subject to a "result_format" template, with each value expanded
>> into the specified template.
>> 
>> If instead the desired result elements are built from multiple MongoDB
>> columns, via some MongoDB "projection" template, then "result_attribute"
>> should not be used, and the user can specify the relevant projection
>> instead.
>> 
>>> Consider this data set:
>>> { "first": "hamid", "last": "maadani", "domain": "dexo.tech", active: 1, 
>>> "other": "some other field
>>> 1"}
>>> { "first": "viktor", "last": "dukhovni", "domain": "postfix.org", active: 
>>> 1, "other": "some other
>>> field 2"}
>>> { "first": "wietse", "last": "venema", "domain": "postfix.org", active: 0, 
>>> "other": "some other
>>> field 3"}
>> 
>> In practive you'd always want a mailbox address, and often also the
>> associated primary email address (for canonical_maps):
>> 
>> filter = { "address": "ha...@dexo.tech"
>> , "mail": "hamid.maad...@dexo.tech"
>> , "maildrop": "ha...@imap1.dexo.tech"
>> , "maildir": "dexo.tex/hamid/"
>> , active: 1 }
>> 
>> So that mail addressed to "address" is canonicalised to "mail" in
>> headers, but rewritten to "maildrop" for delivery to the right server,
>> where (on that server) "maildir" is the relative path to the deliver to.
>> 
>> Each user would have one or more input "address" values that
>> canonicalise to the same primary address, and route to the same
>> maildrop and ultimately maildir.
>> 
>>> Let's say I need mail path for all active users, as well as their last name.
>> 
>> This makes no sense and is not useful. The result elements are not of
>> the same semantic type. The "last name" is not a maildir path. You'd
>> never do this.
>> 
>> Furthermore, Postfix never needs/wants the whole database, it asks for
>> data matching a specific lookup key (recipient or sender address, a
>> domain or IP address for access(5) lookups ...) and wants just the
>> matching row(s), not a database dump.
>> 
>>> The format for mail path is 'first@domain/'. The filter would be
>>> simple: { "active": 1 }
>> 
>> This is not a useful filter. Instead you'd use, for example:
>> 
>> { "active": 1, "address": "%s" }
>> 
>>> We need to build this projection for the desired result:
>>> { "_id": 0, "last": 1, "mail_path": {"$$concat": ["$$first", "@", 
>>> "$$domain", "/"]} }
>> 
>> A sensible "projection" would then be "maildrop" for virtual_alias_maps,
>> and "maildir" for "virtual_mailbox_maps", ...
>> 
>>> { "_id": 0, "last": 1, "mail_path": {"$$concat": ["$$first", "@", 
>>> "$$domain", "/"]} }
>> 
>> This sort of "concat" operation is a bad idea, because it is prone to
>> collisions, and works poorly when the user's name changes, but the
>> mailbox stays the same, ... It is just bad design. Store the mailbox
>> directly as an explicit fixed string.
>> 
>>> which would return:
>>> maadani,ha...@dexo.tech/,dukhovni,vik...@postfix.org/
>> 
>> which makes no sense.
>> 
>>> 'result_attributes' would be need to be set to :
>>> result_attributes = last, mail_path
>> 
>> See above.
>> 
>>> and I guess the 'projection' attribute would need to be set to something 
>>> like:
>>> projection = 1, {"$$concat": ["$$first", "@", "$$domain", "/"]}
>> 
>> You're working too hard. This sort of thing just encourages bad
>> design choices. Just implement "result_attribute" (typically just
>> one), and "result_format" (ala LDAP) to pick this apart and inject
>> it into some template if need be. Then combine multiple results
>> (if need be) by separating with commas.
>> 
>> You do have to decide how mailing lists are modeled in MongoDB. Are
>> they one row per member? Is it a list of "_id" values? Or a list of
>> email addresses? If the former, how does list expansion work? Can
>> MongoDB do joins as well as projections? ...
>> 
>>> or something similar to this.
>>> Would it not be more beneficial/easier to leave the projection as a JSON 
>>> object and up to the user,
>>> instead of having 'result_attribute'?
>> 
>> No.
>> 
>> --
>> Viktor.

Reply via email to