How to implement OrderGroups in the order-sets feature?


We have started implementing the order-sets feature. We have mostly been using the guidelines from the previous design call and the domain model from here. We intend to implement the first cut and then showcase it in a design call for feedback.

I wanted to understand how to implement OrderGroups. The design page suggests that there is separate order_group table. Should we implement this way or like Obs/ObsGroup?


It is intentional to have an order_group table.

(I have forgotten the reasoning behind this, though.)

Can we implement it like Obs though?


No, this should be implemented like the design page says, with a table for ObsGroup.

Quoting Burke from a comment on that wiki page:

Order groups record the relationship between orders that were ordered a group (i.e., from an order set). There will be metadata relevant to the group (not just the members), which is the reason for the additional table.


Sorry I hadn’t seen the comments on the design page earlier.

In the domain model for order_group though there is no provision to define additional metadata. Can you think of an example when we might need this?

Few more questions:

  1. On the design page, order_set_member has order_set_id and order_set_member_id. The documentation mentions the following.

order_set_id and order_set_member_id are unique internal ids

Do we need multiple ids? Or just order_set_member_id would do. 2. Can we add order_set_member_id on order? It would be to easy to access order_set_member info more easily from the order. eg. sort weight 3. Can we implement order_set_member_attributes. The use case was around corollary orders represented as order sets. We wanted to be able to mark a member as primary.


One example I remember hearing about is that for chemotheraphy, drugs are given in “cycles” and one might want to mark “which cycle” as part of the group. (The idea is that we may eventually add more columns to the order_group table, or else order_group_attributes, but this doesn’t have to happen in the first pass.

The idea is that order_set_id is the primary key for the order_set table, and order_set_member_id is the primary key for the order_set_member table. I.e. they are not both unique IDs on the same table. But one order set has many order_set_members.

Interesting point. It makes sense to me. Though I’m curious to hear @burke’s comments. (Aside: remember that order sets can have multi-level members (e.g. an order set can contain another order set) so sorting by sort weight may not be sufficient.)

In principle we want to allow most things to be customizable via attributes, so I don’t see why not. But could you explain the use case more? I can imagine “Boolean primary” being added directly in the data model (rather than needing attributes) if that’s a common use case.

That said, shouldn’t the template be enough of a place to put whatever attribute you want to put?

As an aside, I’ve always been slightly skeptical that storing the hierarchical set members in RDBMS tables with a text template field is the best way of doing things (though I haven’t explored it, or alternatives).

The use case is - For corollary orders, the order set will contain drug A and drug B where drug B is the corollary order for drug A but reverse is not true. So the order set should come up while searching for drug A but not while searching for drug B. This can be achieved by having the ability to mark order set members as “primary”. Also a scenario could arise where we need to mark more than one order set members as “Primary” so that the order set shows up by searching for multiple order set members.

I see the point in having a “Boolean Primary” which will suffice for this use-case but I think adding attributes will be a generic way in case we need to add more attributes later (can’t think of any as of now).

Adding order_set_attribute for custom attributes of order set metadata, order_set_member_attribute to do the same for a membership in an order set, and/or order_group_attribute to store custom data specific to a grouping of orders are all fine to include when/if we need them to allow for custom extensions of the model. Of these, I believe order_group_attribute would be the highest priority for the community… but any are okay to do. The “attribute table” pattern can allow more flexibility in design (focus on getting the fundamentals into the model and then look for custom attributes that everyone seems to need and migrate those into the shared model over time). If you have the time & motivation to include attributes for these resources now, that’s fine. A red flag (warning of something wrong) would be any code within the API needing to refer to a specificy order_set_attribute or order_set_member_attribute. The platform & API can know & allow custom extensions through the attribute pattern, but should never mention or use a specific attribute (since doing so would mean that it’s no longer custom, but should be part of the core model).

While it’s reasonable to want to be able to associate the specific entry in an order set that led to an order being placed, I would be concerned about making such a tight linkage at the database layer. Order Sets need to be able to be easily edited & adjusted to meet changing needs over time and having foreign keys from patient data could be overly constrictive. If the primary motivate is for retaining sort weight, then I would favor creating something like order_group_member table with sort weight to record relative ranking of grouped orders at the time they are placed and avoiding creating constraints that prevent order set metadata from being easily maintained (and revised) over time.

I was assuming that if we wanted an order set to appear when drug A is ordered (e.g., show drug A & drug B in an order set), we would add a concept_order.order_set that would point to the order set to be used when drug A is ordered – i.e., the orderable concept would determine the behavior for ordering itself. That’s the model we have used locally, but I can see that OpenMRS is in a world where the concept dictionary is often centrally managed and through workflows that may not match with local ordering needs. So, it might be desirable to move this control from concept dictionary management into order set management. That’s fair. In that case, I would still prefer something like order_set_for_concept that would explictly define which order set should be shown when an orderable concept is ordered. I’m not a fan of scanning order set metadata to infer what order sets should be shown when someone orders something. All that said, perhaps using order_set_member_attribute could be a reasonable short-term solution until we can work through the design.

In this case I wonder if we should be thinking harder about what the default platform behavior is for searching amongst order sets. I’d rather not automatically decide that we need attributes now, if the real use case is searching, and we haven’t yet described how that should work.

E.g. I could imagine a boolean “searchable” field on order_set_member, and an OrderService.getOrderSetsWithMember(Concept) that respects it.

We are developing order set implementation. We are introducing order group as part of this. So, the Encounter service is required to change to persist the order groups as well. So, the individual orders will continue to use the existing API to persist the drug orders. The order group will have separate API to persist the order group with associated orders.

We will be using the associations in the contract as

Encounter has many OrderGroups OrderGroup has many Orders

So, the orders associated with group will be saved with it.

I have sent the above content in email and Darius Reply as follows.

I don’t quite understand the question.

Note that there will be Orders that are not in any OrderGroup. So Encounter probably needs to have both “orders” and “orderGroups” properties.

@darius Yes, we will be adding orderGroups property. Thats exactly we want to confirm.

We will not be touching orders properties and it will work as before.

We will save orderGroup with orders if the orders come from orderSet.

Why do we have encounter_id in order_group?

As per new design structure Order table has a reference to order_group_id as well as encounter_id (For Order Set implementation we have introduced a new table as order_group), and order_group table has a reference to encounter_id. Now, how should we approach the design when we edit an existing order (in same or different encounter) ?

Because we have encounter_id in both order table and order_group table, when we modify an existing order in different encounters how are we going to link existing order_group_id to newly created order( keeping in mind that now encounter_id in order_group and encounter_id in newly updated order will be different). This actually creates a mismatch in data.

The original intent was order groups would never span encounters. If you revise an order that was in a group, then it would be linked to the previous order, but not directly to the group – i.e., orders revised in subsequent encounters would be related to the original grouping through order.getInitialOrder().getOrderGroup() (where getInitialOrder() returns the start of the previous order chain).

Consider this example:

  • On Monday, a user orders drugs within an Order Set A, including Drug X.
  • Drug X order is in an order group, both are linked to Monday’s encounter.
  • On Thursday, they use Order Set B, which also includes Drug X, and end up revising the Drug X order.
  • Revised Drug X order is in a separate order group, both are linked to Thursday’s encounter.
  • Revised Drug X order’s previousOrder points to the original order for Drug X in encounter A and in its original order group. The revised Drug X order is not in the original order group; rather, it’s relationship to the original order group is inferred through it’s link to the previous order in that group.

As asked by Darius, this is the link to development work that has been done till now.

Apart from these files the other work is on OrderSet, OrderGroup models etc. {{ Around 8 commits since Nov,16 containing the work done yet. }}

Thanks Achinta