0

Lets say I have an object which only contains an array

public class A 
{
       [BsonId]
       public ObjectId Id;
       public int[] arr;

       public A()
       {
            arr = new [5];
       }

}

when I want to update a certain index in the array by Id,

and the Id couldn't be found i want to insert the new object to the db, and when it is inserted

it suppose to have this provided Id and an arr with the provided value on the provided index.

so far so good, BUT, it doesn't happen.

//receiving ObjectId id, int input_index, int input_value

var filter = Builders<A>.Filter.Eq(x => x.Id, id);
var options = new UpdateOptions()
{
    IsUpsert = true
};
var update = Builders<A>.Update.Set(x => x.arr[input_index], input_value);

//executing the query....

Instead, the Id is inserted OK, BUT the array is becoming an int value with the provided value, instead of an array.

Is that a known bug? is there anyway around it?

TIA

Refrence for older question but it was 2 years ago: here

EDIT

Im registering the arr with default vals:

if (!BsonClassMap.IsClassMapRegistered(typeof (A)))
            {
                BsonClassMap.RegisterClassMap<A>(map =>
                {
                    map.AutoMap();
                    map.SetIgnoreExtraElements(true);
                    map.GetMemberMap(c => c.arr)
                        .SetDefaultValue(new int[5] {0, 0, 0, 0, 0});
                });
            }

Also tried to add tags instead of registerMap:

[BsonDefaultValue(new int[5] {0, 0, 0, 0, 0})]
[BsonIgnoreIfDefault]
public int[] arr {set;get;}

and Im receiving:

An error occurred while deserializing the arr property of class DatabaseManager.MongoEntities.A: Cannot deserialize a 'int[]' from BsonType 'Document'.

Community
  • 1
  • 1
Ori Refael
  • 2,888
  • 3
  • 37
  • 68
  • I assume that if there aren't 5 elements in the array then only those that are present are populated and any excess are ignored? – BanksySan Mar 29 '16 at 21:42

1 Answers1

1

Depending on your querying, the fact that it's stored as an integer instead of an array might not matter.

Consider the collection with:

/* 1 */
{
    "_id" : ObjectId("56faeabd4e7309356aa1a0ba"),
    "arr" : [ 
        1, 
        2, 
        3
    ]
}

/* 2 */
{
    "_id" : ObjectId("56faeac74e7309356aa1a0bb"),
    "arr" : 2
}

The contains type queries still work as expected, e.g.:

db.collection.find({arr: 2})

Still returns both these documents.

Problems would arise is you wanted to do a other array-ish updates, like $push, $pop etc. or $size.

The serializer

Here's an example of the custom deserialization into your type.

using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;

class Program
{
    static void Main(string[] args)
    {
        BsonSerializer.RegisterSerializer(new MySerializer());

        var client = new MongoClient();
        var database = client.GetDatabase("test");
        var collection = database.GetCollection<A>("upsertArray");

        var docs = collection.Find(new BsonDocument()).ToList();
    }
}

class A
{
    public int[] Arr { get; set; }
    public ObjectId Id { get; set; }
}

class MySerializer : SerializerBase<A>
{
    public override A Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var doc = BsonDocumentSerializer.Instance.Deserialize(context);

        var ints = new int[5];

        var arr = doc["arr"];

        if (arr.IsBsonArray)
        {
            var array = arr.AsBsonArray;

            for (var i = 0; i < 5; i++)
            {
                if (i < array.Count)
                {
                    ints[i] = array[i].AsInt32;
                }
                else
                {
                    break;
                }
            }
        }
        else
        {
            ints[0] = arr.AsInt32;
        }

        return new A { Arr = ints, Id = doc["_id"].AsObjectId };
    }
}
BanksySan
  • 27,362
  • 33
  • 117
  • 216
  • it IS making problems, because it fails to cast the document to the actual type, in this example: A – Ori Refael Mar 29 '16 at 21:18
  • @OriRefael Ah... yes, you'll need a custom serializer. – BanksySan Mar 29 '16 at 21:32
  • @OriRefael Just added code for the custom deserializer. Is this the behaviour you were thinking of? – BanksySan Mar 29 '16 at 22:08
  • its too late atm, ill probably check tomorrow and give you an answer – Ori Refael Mar 29 '16 at 22:33
  • ok, thanks for the idea with serializing. im still having problems with the serializer that you provided me when im converting it to the object i really need. what I DO want to ask you, and i will accept your answer afterwards, is the question i put in the edit. – Ori Refael Mar 30 '16 at 09:59
  • although im still having problems, it seems like you still answered my main question, so i will accept you answer :0 – Ori Refael Mar 30 '16 at 10:17
  • If you want to chuck a new question up then I'll help if I can. Note that i only implemented the Deserialization, not the serialization. – BanksySan Mar 30 '16 at 10:29