Search code examples
mongodb-.net-driver

How to serialize BsonDocument without null fields or empty objects


How to serialize BsonDocument without null fields or empty objects?

For example

{
    "key1" : null,
    "key2": 100
}

Should be serialized to:

{
   "key2": 100
}

Also, empty objects should be ignored:

{
    "key1" : { },
    "key2": 100
}

Should be serialized to:

{
   "key2": 100
}

Solution

  • NOTE: I assume you're speaking about serialization an entity to BsonDocument since operation on BsonDocument will be modifying, not serialization.

    To ignore null value, it's enough to specify BsonIgnoreIfNull attribute

        public class Entity
        {
            [BsonIgnoreIfNull]
            public BsonDocument Key1 { get; set; }
            [BsonIgnoreIfNull]
            public string Key2 { get; set; }
        }
    

    or via static configuration:

        BsonClassMap.RegisterClassMap<Entity>(b =>
        {
            b.AutoMap();
            b.GetMemberMap<BsonDocument>(i => i.Key1).SetIgnoreIfNull(ignoreIfNull: true);
            b.GetMemberMap<string>(i => i.Key2).SetIgnoreIfNull(ignoreIfNull: true);
        });
    

    however, to ignore the empty document value, you have to create a custom serializer, something like below:

        // use it as a starting point
        public class CustomEntitySerializer : SerializerBase<Entity>
        {
            public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, Entity value)
            {
                context.Writer.WriteStartDocument();
                foreach (var field in value.GetType().GetProperties())
                {
                    var fieldValue = field.GetValue(value);
                    if (fieldValue == null ||
                        (fieldValue is BsonValue v && v.IsBsonNull) ||
                        fieldValue is BsonDocument d && d.ElementCount == 0)
                    {
                        // skip
                    }
                    else
                    {
                        context.Writer.WriteName(field.Name);
                        var serializer = BsonSerializer.LookupSerializer(field.PropertyType);
                        serializer.Serialize(context, args, fieldValue);
                    }
                }
                context.Writer.WriteEndDocument();
            }
        }
    

    and then apply this serializer in this way:

        [BsonSerializer(typeof(CustomEntitySerializer))]
        public class Entity
        {
            [BsonIgnoreIfNull]
            public BsonDocument Key1 { get; set; }
            [BsonIgnoreIfNull]
            public string Key2 { get; set; }
        }
    

    or via global static configuration:

        BsonSerializer.RegisterSerializer<Entity>(new CustomEntitySerializer());