Couchbase Lite ArrayObjects (anyone run into corruption on the way out of the db?)


#1

(Couchbase Lite 2.1) Have any of you experienced Couchbase Lite ArrayObjects being corrupted when retrieved from the database? I have reason to believe they are always going into the database properly, but I’m having intermittent results when they come out of it. I’ve got a relatively simple Couchbase Lite ArrayObject that is made of some ints and one datetimeoffset as string. Sometimes I see it converted to Null. Sometimes to a Long of zero (0), but I’m really looking for its iEnumerator to have size of [6] consistently. Running same code over any over again. I get about a 50% rate of successfully pulling the cbl arrayobject out intact. Very odd issue. Before I post code, I wanted to just generally ask if anyone had seen intermittent results when using them.


#2

No, there’s no known issue like that. What platform of Couchbase Lite? Can you reduce this to a repeatable test case? If not, could you post the code you use to save and read the data?


#3

What platform of Couchbase Lite?: C# / .Net Standard Project / Xamarin Forms.
Can you reduce this to a repeatable test case? : I will attempt to put aside a simple scenario of code that can replicate the issue.
If not, could you post the code you use to save and read the data?: . If I’m unable to set aside a simpler test scenario that duplicates the issue I will redact the code a bit and post it.

Side Question: In general, C# .NET Standard Users, how are you handling the mutable doc preparation for ‘complex’ models? We seem to be fine with POCO classes. Ones where there are just any number of int, string, simple data types etc. We are only noticing this issue when we attempt a ToDictionary of complex objects. How are other C# users handling adding dictionary <string, object> of complex objects? And when I say “complex” I really just mean any model that has a list or array of other very simple models in it (a list of MyOtherType which just has ints in it or datetimeoffset parameters). IF any of you Xamarin Forms fellow users have an example of how you are doing a ToDictionary of your complex objects (and have a github out there I can stare it) it may just be how we are handling the adding of the complex objects into the mutable doc for saving to the database. We are in general just using JSON NET to serialize the overall object (which includes the list of other objects and other simple data types), and then we are then deserializing into <string,object> dictionary. I don’t know if this is properly handling the sub-objects properly.

I’ll post additional supporting information hopefully within the day. I have to imagine this is a scenario that a lot of users will end up bumping up against, so I think the time spent showing generically how to handle it, it would be helpful to all C# Xamarin Forms potential users.

Long Story Short: We are able to save and retrieve simple POCOs fine. It is when those POCO C# classes have a list or array of other simple models that we run into issues getting dictionary <string, object> setup properly for the mutable doc for the sake of saving. About 50% of the time, the couchbase lite array that results in the original saving comes out of the database intact, other times its a single ienumerably couchbase lite array of value {null} or zero(o).


#4

Just a quick side-note - My issue is very similar to this post: https://stackoverflow.com/questions/51930613/couchbase-mobile-2-0-set-array-in-mutabledocument


#5

@borrrden is our .NET expert … any idea what might be wrong, Jim?


#6

I don’t know if this helps any, but this is how the list involved looks in the mutabledoc just prior to save to db. It looks to be in an acceptable format. Also, it does not error out. No exceptions are seen as it saves.


#7

In general the way I like to do it is to have a sort of ToCouchbaseObject method (similar to ToString) on every POCO object that needs to be converted. If another class has a reference to this class, then inside of its ToCouchbaseObject method it will call the subobject’s ToCouchbaseObject method and store that inside. This way you don’t have to bother with complex loops or anything.

With regards to the problem I’d need to see a specific example. Could you show a before and after of one entire document (in a gist if it is large)?


#8

We are beginning to wonder if its just how we are doing our repository’s GetAll… For example sake…

    public List<Dictionary<string, object>> GetAll<T>(string clientId)
    {
        var listDictionary = new List<Dictionary<string, object>>();
        try
        {
            using (var query = QueryBuilder.Select(SelectResult.All())
                .From(DataSource.Database(_database))
                .Where(Expression.Property("_type").EqualTo(Expression.String(typeof(T).Name))
                .And(Expression.Property("tag").EqualTo(Expression.String(clientId)))))
            {
                // Run the query and build return list
                var results = query.Execute().ToList();
                foreach (var result in results)
                {
                    listDictionary.Add(result?.GetDictionary(DatabaseName)?.ToDictionary(x => x.Key, x => x.Value));
                }
            }
        }
        catch (Exception e)
        {
            e.Report();
        }
        return listDictionary;
    }

That listDictionary intermittently does not fully hold the couchbase lite array’s contents properly.


#10

I don’t see anything standing out other than the superfluous use of the ToDictionary() LINQ method (there is already a ToDictionary() method on IDictionaryObject itself which will return a Dictionary<string, object>. Perhaps that will work better? I’d still need to see an example of what is going in, and what is coming out, to make a more detailed theory.


#11

Excuse my delayed response, but I did finally get it working by removing the superfluous linq.

listDictionary.Add(result?.GetDictionary(DatabaseName)?.ToDictionary());

This offers more consistent results… than our previously utilized…

listDictionary.Add(result?.GetDictionary(DatabaseName)?.ToDictionary(x => x.Key, x => x.Value));
}