在单个查询中添加和删除数组

时间:2015-08-24 13:44:03

标签: node.js mongodb mongodb-query

我想进行一个查询,其中我想要知道用户喜欢或不同于我的状态,现在我想在单个查询上进行,以便我不会从我的NODEJS服务器调用数据库2次,做任何解决了我的问题。

For Add我们正在使用     collection.update({_ id:id},         {$ pull:{             ' user_id':' xxxx-xxxx-xxxx-xxxx' }         }     );

For Remove我们正在使用

collection.update({ _id: id },
    { $push: { 
        'user_id': 'xxxx-xxxx-xxxx-xxxx' } 
    }
);

现在我想在一个查询中同时使用它们,就像在fruit数组中应用present一样,如果不添加则删除它。

1 个答案:

答案 0 :(得分:2)

MongoDB不允许$pull$push或任何其他操作在单个语句中更新相同的“路径”(因此是单个数组)。这主要与逻辑处理服务器端有关,其中更新操作从不被视为在语句中进行排序。

示例:

{
   "responses": [
       { "user": "Tom", "status": "like" },
       { "user": "Sarah", "status": "unlike" }
   ]
}

这并不是很有意义,但你不能这样做:

db.collection.update(
    {},
    {
        "$pull": { "responses": { "user": "Tom", "status": "like" },
        "$push": { "responses": { "user": "Tom", "status": "unlike" }
    }
)

由于此处的单个操作在“响应”的“相同路径”上包含$push$pull。无论你构建语句,都不需要以任何顺序执行。

虽然我们可以“匹配”“Tom”的位置并将其“状态”改为“不同”,但更好的模式是:

{
    "likes": ["Tom"],
    "unlikes": ["Sarah"],
    "likesTotal": 1,
    "unlikesTotal": 1,
    "totalScore": 0
}

这意味着如果我想更改“Tom”的“投票”,那么您可以在.bind操作的帮助下创建这样的结构,以启用单个请求和响应:

var bulk = db.collection.initializeOrderedBulkOp();

// Cast "Tom's" unlike where they had a "like" already
bulk.find({
    "likes": "Tom",
    "unlikes": { "$ne": "Tom" }
}).updateOne({
    "$pull": { "likes": "Tom" },
    "$push": { "unlikes": "Tom" },
    "$inc": {
        "likesTotal": -1,
        "unlikesTotal": 1
    }
]);

// Cast "Tom's" new vote where nothing was there at all
bulk.find({
    "unlikes": { "$ne": "Tom" },
    "likes": { "$ne": "Tom" }
}).updateOne({
    "$push": { "unlikes": "Tom" },
    "$inc": {
        "unlikesTotal": 1,
        "totalScore": -1
    }
});

bulk.execute();

这会产生一个非常好的模式。这里的每个更新操作不仅基本上是“原子的”,因为通过对单独的文档属性进行操作,允许每个修饰符执行而不会发生冲突。此外,作为“批量”操作,满足所有可能条件的“两个”更新操作的请求将在单个请求中发送,并在单个响应中接收。

当然,您的“客户端”逻辑还应该知道谁对某个特定项目“喜欢/不喜欢”的当前状态,但在通用API中强制执行此操作是一种很好的做法。

它可以检查数组,并且还可以检查有用的计数器以查找常规数据和一般查询目的,而无需“计算”数组的长度或匹配类型。