2

I'm trying to create a new field in all my documents in a collection. That field will be an array with another field's value as (for now) the single value.

This is my code:

var builder = new UpdateDefinitionBuilder<Member>();
var update = builder.AddToSet(f => f.Sids, "$Sid");

var models = new WriteModel<Member>[]
{
    new UpdateManyModel<Member>(FilterDefinition<Member>.Empty, update)
};

new MongoClient().GetDatabase("mydb").GetCollection<Member>().BulkWrite(models);

It almost worked: the new field (Sids) was created as an array, but with the literal value $Sid instead of the value from the Sid field.

What am I missing?

Anderson Pimentel
  • 5,086
  • 2
  • 32
  • 54

2 Answers2

2

The dollar sign in updates is not interpreted the same way as it is in Aggregation Framework. Old stackoverflow thread here.

As a workaround you can use $out operator which will replace existing collection with result of aggregation pipeline.

col.Aggregate()
   .AppendStage<BsonDocument>(
                    BsonDocument.Parse("{ $addFields: { \"Sids\": [\"$Sid\"] }}"))
   .Out("col");
mickl
  • 48,568
  • 9
  • 60
  • 89
2

great answer by mickl...

starting with mongodb server v4.2 you can refer to existing fields of the documents using aggregation pipeline stages as described here.

in case anybody's interested here's a sample program using MongoDB.Entities doing the same:

using MongoDB.Entities;
using System;
using System.Collections.Generic;

namespace StackOverflow
{
    public class Program
    {
        public class Member : Entity
        {
            public string Sid { get; set; }
        }

        private static void Main(string[] args)
        {
            new DB("test");

            var members = new List<Member>();

            for (int i = 1; i <= 10; i++)
            {
                members.Add(new Member
                {
                    Sid = Guid.NewGuid().ToString()
                });
            }

            members.Save();

            DB.Update<Member>()
              .Match(_ => true)
              .WithPipelineStage("{ '$set': { 'Sids': ['$Sid'] } }")
              .WithPipelineStage("{ '$unset': ['Sid'] }")
              .ExecutePipeline();
        }
    }
}
Dĵ ΝιΓΞΗΛψΚ
  • 5,068
  • 3
  • 13
  • 26
  • 1
    Im currently using your library in one of our projects. It would be great if we could override the save async or save methods in our entites - This would allow us to fire domain events and do auditing on our entites conveniently. Currently we have to do this in the service layer . I wasnt sure how to reach you with this suggestion. – cl0ud Aug 29 '19 at 07:14
  • @cl0ud i will look in to it. could you pls open a [new issue on github](https://github.com/dj-nitehawk/MongoDB.Entities/issues/new) for this? it would help if you show me an example of what you're trying to do, even if it's pseudo code. thanks! – Dĵ ΝιΓΞΗΛψΚ Aug 29 '19 at 09:14
  • Will post a issue when I get home from work, thanks for your reply. Im also open to creating a pull request and adding it in myself! – cl0ud Aug 29 '19 at 09:25