我遇到了MongoDB中与$in
相关的问题,但没有得到理想的结果。
这是我的MongoDB集合数据,以便更好地实现可视化
[
{
"_id" : ObjectId("5aeaf7c73c3e9de82d91e439"),
"companyID" : "4",
"accounts" : [
{
"_id" : ObjectId("5aeaf7c720262a1db759edf5"),
"userID" : "1",
"preferences" : [
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeaf7c720262a1db759edf7"),
"preferenceID" : "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T11:51:35.509Z"),
"updatedAt" : ISODate("2018-05-03T11:51:35.509Z")
},
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeaf7c720262a1db759edf6"),
"preferenceID" : "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T11:51:35.509Z"),
"updatedAt" : ISODate("2018-05-03T11:51:35.509Z")
}
]
}
],
"__v" : 0
},
{
"_id" : ObjectId("5aeafe693c3e9de82d91e43a"),
"companyID" : "5",
"accounts" : [
{
"_id" : ObjectId("5aeafe698b1d5f2057419c99"),
"userID" : "1",
"preferences" : [
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe698b1d5f2057419c9b"),
"preferenceID" : "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:19:53.436Z"),
"updatedAt" : ISODate("2018-05-03T12:19:53.436Z")
},
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe698b1d5f2057419c9a"),
"preferenceID" : "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:19:53.436Z"),
"updatedAt" : ISODate("2018-05-03T12:19:53.436Z")
}
]
}
],
"__v" : 0
},
{
"_id" : ObjectId("5aeafe6d3c3e9de82d91e43b"),
"companyID" : "6",
"accounts" : [
{
"_id" : ObjectId("5aeafe6d8b1d5f2057419c9c"),
"userID" : "1",
"preferences" : [
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe6d8b1d5f2057419c9e"),
"preferenceID" : "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:19:57.331Z"),
"updatedAt" : ISODate("2018-05-03T12:19:57.331Z")
},
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe6d8b1d5f2057419c9d"),
"preferenceID" : "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:19:57.331Z"),
"updatedAt" : ISODate("2018-05-03T12:19:57.331Z")
}
]
},
{
"_id" : ObjectId("5aeafe738b1d5f2057419c9f"),
"userID" : "2",
"preferences" : [
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe738b1d5f2057419ca1"),
"preferenceID" : "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:20:03.987Z"),
"updatedAt" : ISODate("2018-05-03T12:20:03.987Z")
},
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe738b1d5f2057419ca0"),
"preferenceID" : "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:20:03.987Z"),
"updatedAt" : ISODate("2018-05-03T12:20:03.987Z")
}
]
},
{
"_id" : ObjectId("5aeafe778b1d5f2057419ca2"),
"userID" : "3",
"preferences" : [
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe778b1d5f2057419ca4"),
"preferenceID" : "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:20:07.062Z"),
"updatedAt" : ISODate("2018-05-03T12:20:07.062Z")
},
{
"emailNotification" : true,
"smsNotification" : true,
"pushNotification" : false,
"webNotification" : false,
"lastUpdatedBy" : "SYSTEM",
"_id" : ObjectId("5aeafe778b1d5f2057419ca3"),
"preferenceID" : "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt" : ISODate("2018-05-03T12:20:07.062Z"),
"updatedAt" : ISODate("2018-05-03T12:20:07.062Z")
}
]
}
],
"__v" : 0
}]
我想从数据中获取什么。 我正在尝试根据公司ID& amp;获取每个公司的用户偏好。 userID,但适用于多个公司和多个用户,而不是单个用户。
比如说我有这个输入数据[
userID:2 ,
companyID:6 ]
和[userID:1
,companyID:4
]
基于上面添加的文档数据的输出应该是
[
{
"userID":2,
"companyID":6,
"preferences":[] // the preferences from that db
},
{
"userID":1,
"companyID":4,
"preferences":[] // their respective preferences array
}
]
以上是所需的输出,现在我的解决方法
方法
我在对象的表单数组中获取输入参数
input_json = [{
"userID":2,
"companyID":6
},
{
"userID":1,
"companyID":4
},
]
获取输入JSON后,我正在制作两个不同的数组用户数组,公司的数组,user_array
将保存所有用户ID,company_array
将保存所有的公司ID此
user_array = input_json.map((elem)=>elem.userID) // which will hold all the company ID
//For the above input_json, the value of `user_array` would be
// `user_array: [2,1]`
company_array = input_json.map((elem)=>elem.userID)
//For the above input_json, the value of `company_array` would be
// `company_array`:[4,4]
获得userIDs&的值后companyID单独,我使用$ in来匹配MongoDB上的查询来匹配数组
中的iddb.collection.find({
userID:{
$in:user_array
},
accounts.companyID:{
$in:company_array
}
})
我没有得到理想的结果,我希望将userID和companyID用作获取数据的唯一键。
但正在发生的是匹配user_array
中的userID和company_array
中的companyID。但是,我希望检查userID
和companyID
是否获得数据。
任何帮助都会被贬低:)
答案 0 :(得分:3)
只需在样本上稍微扩展一下就可以包含"可能"您的请求数组实际上要求来自同一公司的多个用户的情况。
基本"查询" condition只是重新映射输入数组并在$or
查询参数中使用它。出来像:
{
"$or": [
{
"companyID": "6",
"accounts.userID": "3"
},
{
"companyID": "6",
"accounts.userID": "2"
},
{
"companyID": "4",
"accounts.userID": "1"
}
]
}
这将匹配"文档",但相应的"用户"信息包含在"accounts"
数组中。为了仅检索那些项目,我们需要应用$filter
条件来简单地保持那些符合条件的数组条目。然后,只需要在剩余的数组内容上使用$unwind
,然后使用$project
将一个小文档重新整理为所需的输出格式。
整个生成的语句将如下所示:
Company.aggregate([
{ '$match': {
'$or': [
{ companyID: '6', 'accounts.userID': '3' },
{ companyID: '6', 'accounts.userID': '2' },
{ companyID: '4', 'accounts.userID': '1' }
]
}},
{ '$addFields': {
accounts: {
'$filter': {
input: '$accounts',
cond: {
'$or': [
{ '$and': [
{ '$eq': [ '$companyID', '6' ] },
{ '$eq': [ '$$this.userID', '3' ] }
] },
{ '$and': [
{ '$eq': [ '$companyID', '6' ] },
{ '$eq': [ '$$this.userID', '2' ] }
] },
{ '$and': [
{ '$eq': [ '$companyID', '4' ] },
{ '$eq': [ '$$this.userID', '1' ] }
] }
]
}
}
}
}},
{ '$unwind': '$accounts' },
{ '$project': {
userID: '$accounts.userID',
companyID: 1,
preferences: '$accounts.preferences'
}}
])
查询的$or
内容和$or
的$filter
的其他形式基本上是从输入数组中生成的,如下所示:
let query = {
$or: input.map(({ userID, companyID }) =>
({ companyID, 'accounts.userID': userID }))
};
let condition = input.map(({ userID, companyID }) =>
({ "$and": [
{ "$eq": ["$companyID", companyID] },
{ "$eq": ["$$this.userID", userID] }
]})
);
然后在管道构造的其余部分中用作参数,这主要是静态的。请注意$filter
中的"cond"
用法需要"聚合逻辑运算符"它根据测试结果返回一个布尔值。因此它们与形式函数中的查询运算符不同。
相同"配对"适用于每个$or
条件,以便在查找与该组合匹配时,会考虑帐户数组中的"companyID"
值以及当前"userID"
值。在$filter
内,重要的是检查数组外部的"companyID"
,同时检查当前数组元素。
我们无法使用标准positional $
operator投影执行此操作的原因主要是因为查询中存在$or
条件。还存在"多个匹配"的附加约束。在这里添加了用于演示,但由于查询中的$or
,MongoDB无法确定哪些"条件和#34;无论如何,实际上对任何单个文档都满足元素匹配位置。
所以如果你想要"一个"那真的不重要。用户要匹配来自每个公司或多个",因为需要应用相同的聚合过滤器以便提取正确的"用户"细节无论如何。
完整的演示清单如下:
const { Schema } = mongoose = require('mongoose');
const uri = 'mongodb://localhost/test';
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
let input = [
{
"userID": 3,
"companyID": 6
},
{
"userID": 2,
"companyID": 6
},
{
"userID": 1,
"companyID": 4
}
];
// non-strict for testing
const Company = mongoose.model('Company', new Schema({},{ strict: false }));
const log = data => console.log(JSON.stringify(data, undefined, 2));
(async function() {
try {
const conn = await mongoose.connect(uri);
// Clean data to actually be matching strings
input = input.map(({ userID, companyID }) =>
({ userID: userID.toString(), companyID: companyID.toString() }));
let query = {
$or: input.map(({ userID, companyID }) =>
({ companyID, 'accounts.userID': userID }))
};
log(query);
let condition = input.map(({ userID, companyID }) =>
({ "$and": [
{ "$eq": ["$companyID", companyID] },
{ "$eq": ["$$this.userID", userID] }
]})
);
log(condition);
let result = await Company.aggregate([
{ "$match": query },
{ "$addFields": {
"accounts": {
"$filter": {
"input": "$accounts",
"cond": { "$or": condition }
}
}
}},
{ "$unwind": "$accounts" },
{ "$project": {
"userID": "$accounts.userID",
"companyID": 1,
"preferences": "$accounts.preferences"
}}
]);
log(result);
mongoose.disconnect();
} catch(e) {
console.error(e)
} finally {
process.exit()
}
})()
这会产生如下输出:
[
{
"_id": "5aeaf7c73c3e9de82d91e439",
"companyID": "4",
"userID": "1",
"preferences": [
{
"emailNotification": true,
"smsNotification": true,
"pushNotification": false,
"webNotification": false,
"lastUpdatedBy": "SYSTEM",
"_id": "5aeaf7c720262a1db759edf7",
"preferenceID": "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt": "2018-05-03T11:51:35.509Z",
"updatedAt": "2018-05-03T11:51:35.509Z"
},
{
"emailNotification": true,
"smsNotification": true,
"pushNotification": false,
"webNotification": false,
"lastUpdatedBy": "SYSTEM",
"_id": "5aeaf7c720262a1db759edf6",
"preferenceID": "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt": "2018-05-03T11:51:35.509Z",
"updatedAt": "2018-05-03T11:51:35.509Z"
}
]
},
{
"_id": "5aeafe6d3c3e9de82d91e43b",
"companyID": "6",
"userID": "2",
"preferences": [
{
"emailNotification": true,
"smsNotification": true,
"pushNotification": false,
"webNotification": false,
"lastUpdatedBy": "SYSTEM",
"_id": "5aeafe738b1d5f2057419ca1",
"preferenceID": "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt": "2018-05-03T12:20:03.987Z",
"updatedAt": "2018-05-03T12:20:03.987Z"
},
{
"emailNotification": true,
"smsNotification": true,
"pushNotification": false,
"webNotification": false,
"lastUpdatedBy": "SYSTEM",
"_id": "5aeafe738b1d5f2057419ca0",
"preferenceID": "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt": "2018-05-03T12:20:03.987Z",
"updatedAt": "2018-05-03T12:20:03.987Z"
}
]
},
{
"_id": "5aeafe6d3c3e9de82d91e43b",
"companyID": "6",
"userID": "3",
"preferences": [
{
"emailNotification": true,
"smsNotification": true,
"pushNotification": false,
"webNotification": false,
"lastUpdatedBy": "SYSTEM",
"_id": "5aeafe778b1d5f2057419ca4",
"preferenceID": "6fbd6c-4c56-11e8-842f-0ed5f89f718b",
"createdAt": "2018-05-03T12:20:07.062Z",
"updatedAt": "2018-05-03T12:20:07.062Z"
},
{
"emailNotification": true,
"smsNotification": true,
"pushNotification": false,
"webNotification": false,
"lastUpdatedBy": "SYSTEM",
"_id": "5aeafe778b1d5f2057419ca3",
"preferenceID": "6fb118-4c56-11e8-842f-0ed5f89f718b",
"createdAt": "2018-05-03T12:20:07.062Z",
"updatedAt": "2018-05-03T12:20:07.062Z"
}
]
}
]
显示我们只返回了文档中匹配的公司和用户详细信息组合。
注意不确定使用您提供的输入样本是"故意" ,这些值是"数字&#34 ;而不是"字符串",当然它们实际上是"字符串"在它需要匹配的数据中。这是一个简单的代码行,它将数值转换为字符串,当然输入类型和存储类型都已匹配,这当然不是必需的。
同时,猫鼬通常会"演员"正常查询操作下的这些值对于模式中的任何内容,此不会与聚合管道一起发生。您在汇总管道操作中申请匹配的任何条件都需要"您" 自行将值转换为正确的类型。
Mongoose不会这样做,因为它无法做出假设"在聚合流水线阶段,当时呈现的数据与模式所知的状态相同。聚合操作通常是关于重塑文档"并且出于这个原因"架构"不适用于此。