过滤到不在结果数组中包含匹配值

时间:2017-09-20 08:23:17

标签: javascript mongodb mongoose mongodb-query aggregation-framework

我有一个查询,我首先要匹配查找匹配用户的列表,然后从传入的外部用户数组中筛选出匹配项,以便我留下没有的用户ID已经匹配了。

这是匹配架构:

const mongoose = require('mongoose'); // only match two users at a time.
const Schema = mongoose.Schema;

const MatchSchema = new Schema({
    participants: [{
        type: String, ref: 'user'        
    }],
    blocked: {
        type: Boolean,
        default: false
    }
});

以下是带有解释的查询:

db.getCollection('match').aggregate([
               { 
          '$match': {
               '$and': [       
                    { participants: "599f14855e9fcf95d0fe11a7" }, // the current user.
                    { participants: {'$in': [ "598461fcda5afa9e0d2a8a64","598461fcda5afa9e0d111111", "599f14855e9fcf95d0fe5555"] } } // array of external users that I want to check if the current user is matched with.
                ]
            }
        },
        {
            '$project': {
                'participants': 1
            }
        },

返回以下结果:

{
    "_id" : ObjectId("59c0d76e66dd407f5efe7112"),
    "participants" : [ 
        "599f14855e9fcf95d0fe11a7", 
        "599f14855e9fcf95d0fe5555"
    ]
},
{
    "_id" : ObjectId("59c0d76e66dd407f5efe75ac"),
    "participants" : [ 
        "598461fcda5afa9e0d2a8a64", 
        "599f14855e9fcf95d0fe11a7"
    ]
}

我接下来要做的是将参与者数组合并为两个结果形成一个数组。

然后我想从外部用户数组中删除那些匹配的项目,以便我留下尚未匹配的用户ID。

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

如果您不希望这些结果出现在数组中,那么$filter就会结束。

通过使用$or(聚合逻辑版本)构建条件:

layer = null;

如果您有支持它的MongoDB 3.4,请使用$in(再次使用聚合版本):

var currentUser = "599f14855e9fcf95d0fe11a7",
    matchingUsers = [ 
      "598461fcda5afa9e0d2a8a64",
      "598461fcda5afa9e0d111111",
      "599f14855e9fcf95d0fe5555"
    ],
    combined = [currentUser, ...matchingUsers];

db.getCollection('match').aggregate([
  { '$match': {
    'participants': { '$eq': currentUser, '$in': matchingUsers }
  }},
  { '$project': {
    'participants': {
      '$filter': {
        'input': '$participants',
        'as': 'p',
        'cond': {
          '$not': {
            '$or': combined.map(c =>({ '$eq': [ c, '$$p' ] }))
          }
        }
      }
    }
  }}
])

真的没关系。它只是在发送管道之前使用JavaScript构建表达式或让受支持的管道运算符在实际支持它的情况下进行数组比较的区别。

请注意,您还可以使用"隐式"更有效地编写$match。形式为db.getCollection('match').aggregate([ { '$match': { 'participants': { '$eq': currentUser, '$in': matchingUsers } }}, { '$project': { 'participants': { '$filter': { 'input': '$participants', 'as': 'p', 'cond': { '$not': { '$in': ['$p', combined ] } } } } }} ]) ,如图所示。

  

另请注意,您的架构定义存在问题(但与此特定查询无关)。你不能使用" ref"在另一个集合中作为$and的另一个集合,其中StringObjectId的默认值,并且假设已获得的十六进制值)在另一个集合中。这种不匹配意味着_id.populate()功能无效。所以你真的应该纠正这些类型。

     

与此无关。但是你需要确定一些优先事项。