<fieldX>: null OR <hasFiledX>: false flag?

I am in a bit of a dilemma. In my model an array field can have some values, be empty or not be used at all. I am wondering what is the best way to represent the situation when the field is not used. Would it be enough just to have the <fieldX>: null or would it be too confusing, and a flag should be used to simplify things. Namely:

 {
  usesFieldX: false,
  fieldX: null 
 }

This seems cleaner, but the way I see it, we might end up having two sources of truth and the data structure might be less self-explanatory - one needs to know about the relationship between both fields to be able to work with the data properly, while in the first case is more fool-proof.

Example:
A user has permissions to read ([read]), no permissions ([]) or permissions are not applicable (null?).

Can you share your thoughts with me? From your experience, what are the pros and cons of each solution?

Hello @_alex, here are some thoughts:

…an array field can have some values, be empty or not be used at all. I am wondering what is the best way to represent the situation when the field is not used.

The array field has CRUD operations, and these depend upon the application functionality. This is the main consideration. What are the scenarios, in your code / application, you use this array field?

Initially, when a user is created you might know that he or she may have permissions or permissions may not be applicable. In such a case, create a field with permissions_applicable: true / false. If permissions_applicable is true, and you know the permission value(s), include the array field (lets call it, permissions) along with the values in the newly created document. If you don’t know the permission values, do not create the field. At this stage, the field permissions_applicable is enough for further usage in other operations.

Then you update the user’s array field (either push into or pull elements from the array), later. This can happen, only for documents with permissions_applicable: true.

So, whenever you work with this field (users permissions functionality), always use the permissions_applicable field.


For example:

When the user is newly created with db.users.insertOne( ... ), these are possible:

{ _id: 1, name: "John Doe", permissions_applicable: true, other_fields: ... }
{ _id: 1, name: "John Doe", permissions_applicable: true, permissions: [ "read", "write" ], other_fields: ... }
{ _id: 1, name: "John Doe", permissions_applicable: false, other_fields: ... }

When a user is updated with a new permission, or a permission is removed:

db.users.updateOne( { _id: 1, permissions_applicable: true }, { $pull: { permissions: "write" } } )
db.users.updateOne( { _id: 1, permissions_applicable: true }, { $push: { permissions: "delete" } } )

Finally, while querying:

db.users.find( { permissions_applicable: true, ... } )


NOTES:

How the updates on an array field function using $push:

  • The $push operator appends a specified value to an array.
  • If the field is absent in the document to update, $push adds the array field with the value as its element.
  • If the field is not an array, the operation will fail. (Having a null value on the array field may not behave well when you want to add or delete array elements; you have to check if the array field is not null. Checking a field for a null is not very intuitive, I think.)

Also, note that if you use the $pull operator on a non-existing array field, nothing happens (it is not an error).

1 Like

@Prasad_Saya Thank you for sharing your thoughts! This seems like a healthy approach.