使用C#驱动程序更新/删除MongoDB中的子文档

4

我有两个类:

public class Vote
{
    public string VoteId { get; set; }
    public string Question { get; set; }
    public List<VoteAnswer> AnswerList { get; set; }
}

并且:
public class VoteOption
{
    public string OptionId { get; set; }
    public string OptionName { get; set; }
    public double VoteCount { get; set; }
}

如何在 C# 驱动程序中更新/删除 Vote 中的 VoteOption,其中 VoteId = voteIdOptionId = optionId

首先通过以下方式获取 VoteOption

        var v = col.FindOneAs<Vote>(Query.EQ("VoteID", voteId));
        VoteOption vo = v.AnswerList.Find(x => x.OptionId == optionId);

将其设置为某个值:

vo.OptionName = "some option chose";
vo.VoteCount = 1000;

但我不知道下一步如何将这个vo更新为投票父级

如果我想删除这个vo,请告诉我该怎么做!

MongoDB中的数据如下:

{
  "_id" : "460b3a7ff100",
  "Question" : "this is question?",
  "AnswerList" : [{
      "OptionId" : "1",
      "OptionName" : "Option 1",
      "VoteCount" : 0.0
    }, {
      "OptionId" : "2",
      "OptionName" : "Option 2",
      "VoteCount" : 0.0
    }, {
      "OptionId" : "3",
      "OptionName" : "Option 3",
      "VoteCount" : 0.0
    }
    }]
}

请看 $ 运算符:http://docs.mongodb.org/manual/reference/operators/#_S_ - Ian Mercer
4个回答

12

要更新子文档,您可以使用以下方法:

var update = Update.Set("AnswerList.$.OptionName", "new").Set("AnswerList.$.VoteCount", 5);
collection.Update(Query.And(Query.EQ("_id", new BsonObjectId("50f3c313f216ff18c01d1eb0")), Query.EQ("AnswerList.OptionId", "1")), update);

性能分析器:

"query" : { "_id" : ObjectId("50f3c313f216ff18c01d1eb0"), "AnswerList.OptionId" : "1" },
"updateobj" : { "$set" : { "AnswerList.$.OptionName" : "new", "AnswerList.$.VoteCount" : 5 } }

并且要删除:

var pull = Update<Vote>.Pull(x => x.AnswerList, builder => builder.EQ(q => q.OptionId, "2"));
collection.Update(Query.And(Query.EQ("_id", new BsonObjectId("50f3c313f216ff18c01d1eb0")), Query.EQ("AnswerList.OptionId", "2")), pull);

性能分析器:

"query" : { "_id" : ObjectId("50f3c313f216ff18c01d1eb0"), "AnswerList.OptionId" : "2" },
"updateobj" : { "$pull" : { "AnswerList" : { "OptionId" : "2" } } }

另一种方式是更新父文档,以包含修改后的子集合。


直接更新父文档是一个不好的建议。如果“user1”在另一个用户同时更改子文档“optionId: 2”的情况下更改了子文档“optionId: 1”,会怎样呢? - s.meijer

2
// Example function for update like count add like user  using c#    
public PostModel LikeComment(LikeModel like)
{
    PostModel post = new PostModel();

    _client = new MongoClient();
    _database = _client.GetDatabase("post");
    var collection = _database.GetCollection<PostModel>("post");

    var _filter = Builders<PostModel>.Filter.And(
    Builders<PostModel>.Filter.Where(x => x.PostId == like.PostId),
    Builders<PostModel>.Filter.Eq("Comments.CommentId", like.CommentId));

    var _currentLike = collection.Find(Builders<PostModel>.Filter.Eq("PostId", like.PostId)).FirstOrDefault().Comments.Find(f => f.CommentId == like.CommentId).Like;

    var update = Builders<PostModel>.Update.Set("Comments.$.Like", _currentLike + 1);
    collection.FindOneAndUpdate(_filter, update);

    var addUser = Builders<PostModel>.Update.Push("Comments.$.LikeUsers", like.UserId);
    collection.FindOneAndUpdate(_filter, addUser);

    var _findResult = collection.Find(_filter).FirstOrDefault();

    return _findResult;
}

1
//Delete comment
public PostModel delcomment(int postId, int commentId)
{
    _client = new MongoClient();
    _database = _client.GetDatabase("post");
    var collection = _database.GetCollection<PostModel>("post");

    var filter = Builders<PostModel>.Filter.Eq("PostId", postId);

    var update = Builders<PostModel>.Update.PullFilter("Comments",
    Builders<Comments>.Filter.Eq("CommentId", commentId));

    collection.FindOneAndUpdate(filter, update);

    var _findResult = collection.Find(filter).FirstOrDefault();
    return _findResult;
}

1

回答晚了,但是这就是您在没有字符串的情况下执行它的方法。如果您修改属性,则代码将无法编译。第一次在生产代码中使用表达式尝试!他们太棒了!

模型:

class Phone
{
  public string _id { get; set; }
  public string Name { get; set; }
  public DateTime DateCreated { get; set; }

            // Contain multiple lines as subdocument
  public List<Line> Lines { get; set; }
}

class Line
{
   public string Name { get; set; }
   public string PhoneNumber { get; set; }
}

代码:这是我创建更新语句的方式,不依赖于字符串。

var update = new UpdateDocument<Phone>();

// set filter
update.SetFilter(x => x._id == "123456789");

update.AddValueToUpdate(p => p.Name, "New Name");
update.AddValueToUpdate(p => p.Lines[0].Name, "Line 1");
update.AddValueToUpdate(p => p.Lines[1].Name, "Line 2");
update.AddValueToUpdate(p => p.DateCreated, DateTime.UtcNow);


var updateQuery = update.Build();

这就是所需传递给mondo进行更新的内容!
{ "_id" : "123456789" },
{$set:
  {"Name":"New Name","Lines.0.Name":"Line 1","Lines.1.Name":"Line 2","DateCreated":ISODate("2021-04-30T16:04:59.332Z")}
}

如果您希望该代码在此处正常工作,则需要使用辅助类:

using MongoDB.Bson;
using System.Linq.Expressions;
using MongoDB.Bson.Serialization;

class UpdateDocument<T>
{
    /// <summary>
    ///     _id of document to update. 
    /// </summary>
    private string _filter;

    /// <summary>
    ///     Example:
    ///     FirstName, Antonio
    ///     Education.Elementary.Year, 2004
    /// </summary>
    private List<KeyValuePair<string, object>> _valuesToUpdate { get; set; } = new List<KeyValuePair<string, object>>();

    public void SetFilter(Expression<Func<T, bool>> filterDefinition)
    {
        var documentSerializer = BsonSerializer.SerializerRegistry.GetSerializer<T>();
        var where = Builders<T>.Filter.Where(filterDefinition).Render(documentSerializer, BsonSerializer.SerializerRegistry);
        _filter = where.ToJson();
    }

    public void AddValueToUpdate(string name, object value)
    {
        _valuesToUpdate.Add(new KeyValuePair<string, object>(name, value));
    }

    public void AddValueToUpdate(Expression<Func<T, object>> name, object value)
    {
        var memberExpression = name.Body as MemberExpression;
        if (memberExpression == null)
        {
            var unaryExpression = name.Body as UnaryExpression;
            if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert)
                memberExpression = unaryExpression.Operand as MemberExpression;
        }

        var result = memberExpression.ToString();
        result = result.Substring(result.IndexOf('.') + 1);

        if (result.Contains("get_Item"))
            result = Regex.Replace(result, @"(?x) get_Item \( (\d+) \)", m => $"{m.Groups[1].Value}");

        AddValueToUpdate(result, value);
    }

    public string Build()
    {
        if (_valuesToUpdate.Any() == false)
        {
            // nothing to update
            return null;
        }

        /*
update({ 
_id: 7, 
"comments._id": ObjectId("4da4e7d1590295d4eb81c0c7")
},{
$set: {"comments.$.type": abc}
}, false, true
);
            */

        StringBuilder sb = new StringBuilder();

        sb.Append(_filter);
        sb.Append(',');

        sb.Append("{");
        {
            sb.Append("$set:{");
            foreach (var item in _valuesToUpdate)
            {
                sb.Append('"');
                sb.Append(item.Key);
                sb.Append('"');
                sb.Append(':');

                var value = BsonExtensionMethods.ToJson(item.Value);
                sb.Append(value);
                sb.Append(',');
            }
            // remove last comma
            sb.Length--;
            sb.Append('}');
        }
        sb.Append("}");

        return sb.ToString();




    }


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接