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

时间:2013-01-14 05:23:50

标签: c# mongodb mongodb-.net-driver

我有2个班级:

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; }
}

如何更新/删除VoteOption VoteVoteId = voteId中的OptionId = optionId?使用C#驱动程序。

首先我通过以下方式获得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更新为Vote parent的下一步是什么。

而且,如果我要删除此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
    }
    }]
}

4 个答案:

答案 0 :(得分:11)

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

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" } } }

另一种方法是使用修改后的子集合更新父文档。

答案 1 :(得分: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;
}

答案 2 :(得分:0)

//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;
}

答案 3 :(得分:0)

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

型号:

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();




    }


}