简体   繁体   中英

How do I join and project a multi-map index?

I'm struggling to get my head around this one and I know the way to do this is through a custom index. Essentially, I have several collections that share some common properties, one of which is "system id" which describes a many-to-one relationship, eg

// Id() = "component:a"
{
    "Name": "Component A"
    "SystemId": "system:foo"
}

// Id() = "resource:a"
{
    "Name": "Resource A",
    "SystemId": "system:foo"
}

So these are two example objects which live in two different collections, Components and Resources, respectively.

I have another collection called "Notifications" and they have a RecipientID which refers to the Id of one of the entities described above. eg

// Id() = "Notifications/84-A"
{
  "RecipientID": "component:a",
  "Message": "hello component"
}

// Id() = "Notifications/85-A"
{
  "RecipientID": "resource:a",
  "Message": "hello resource"
}

The query that I want to be able to perform is pretty straight forward -- "Give me all notifications that are addressed to entities which have a system of ''" but I also want to make sure I have some other bits from the entities themselves such as their name, so a result object something like this:

{
  "System": "system:foo",
  "Notifications": [{
    "Entity": "component:a",
    "EntityName": "Component A",
    "Notifications": [{
      "Id": "Notifications/84-A",
      "Message": "hello component"
    }]
  }, {
    "Entity": "resource:a",
    "EntityName": "Resource A",
    "Notifications": [{
      "Id": "Notifications/85-A",
      "Message": "hello resource"
    }]
  }]
}

Where I am with it right now is that I'm creating a AbstractMultiMapIndexCreationTask which has maps for all of these different entities and then I'm trying to use the reduce function to mimic the relationship.

Where I'm struggling is with how these map reduces work. They require that the shape is identical between maps as well as the reduce output. I've tried some hacky things like including all of the notifications as part of the map and putting dummy values where the properties don't match, but besides it making it really hard to read/understand, I still couldn't figure out the reduce function to make it work properly.

How can I achieve this? I've been digging for examples, but all of the examples I've come across make some assumptions about how references are arranged. For example, I don't think I can use Include because of the different collections (I don't know how Raven would know what to query), and coming from the other direction, the entities don't have enough info to include or load notifications (I haven't found any 'load by query' function). The map portion of the index seems fine, I can say 'give me all the entities that share this system, but the next part of grabbing the notifications and creating that response above has eluded me. I can't really do this in multiple steps either, because I also need to be able to page. I've gone in circles a lot and I could use some help.

How about indexing the related docs? Something like this (a javascript index):

map("Notifications", (n) => {
      let c = load(n.RecipientID, 'Components');
      let r = load(n.RecipientID, 'Resources');
      
      return {
            Message: n.Message,
            System: c.SystemId || r.SystemId,
            Name: c.Name || r.Name,
            RelatedDocId: id(c) || id(r)
      };
})

Then you can query on this index, filter by the system value, and get all matching notifications docs.

ie sample query:

from index 'yourIndexName' 
where System == "system:foo"

Info about related documents is here:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM