Mongo - 匹配对象键可变的地方
Mongo - Match where object key is variable
我有一个包含以下对象的 Mongo 数据库:
[
{
"link" : "xxxxx.jpg"
"_id" : ObjectId("5501b1648ef0b4eccc41814e"),
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
}
}
]
我正在尝试查询任何处理过的值是假的,但我似乎无法弄清楚如何查询我不知道哪个键匹配的地方。这是否可以不循环遍历所有文档?
配合MongoDB3.4.4,使用聚合框架查询文档。这可以通过 $objectToArray
运算符实现,它允许您将已处理字段中的键映射到 key/value 对数组。该列表将很容易过滤并获得与您所拥有的任何条件相匹配的键。
在下面的示例中,聚合管道包含一个额外的字段,该字段包含与上述具有假值的条件相匹配的键,因此理想情况下它将是一个数组:
db.collection.aggregate([
{ "$addFields": {
"notProcessed": {
"$map" : {
"input": {
"$filter": {
"input": { "$objectToArray": "$processed" },
"as": "el",
"cond": { "$not": "$$el.v" }
}
},
"in": "$$this.k"
}
}
} }
])
产生
{
"_id" : ObjectId("5501b1648ef0b4eccc41814e"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
},
"notProcessed" : [
"original"
]
}
解释
从嵌套表达式开始
{
"$filter": {
"input": { "$objectToArray": "$processed" },
"as": "el",
"cond": { "$not": "$$el.v" }
}
}
$filter
operator { "$objectToArray": "$processed" }
的输入会将 processed
键中的键转换为这个数组:
[
{
"k" : "320",
"v" : true
},
{
"k" : "480",
"v" : true
},
{
"k" : "540",
"v" : true
},
{
"k" : "720",
"v" : true
},
{
"k" : "800",
"v" : true
},
{
"k" : "1080",
"v" : true
},
{
"k" : "original",
"v" : false
},
{
"k" : "iPhone",
"v" : true
}
]
和 $filter
将过滤上述数组以仅包含 v
属性 为 NOT
true
:
的对象元素
[
{
"k" : "original",
"v" : false
}
]
$map
将 return 一个仅包含值
的映射数组
[ { "k" : "original", "v" : false } ] => [ "original" ]
所以你最终只得到
[ "original" ]
结果。
对于较旧的 MongoDB 版本,将很难针对动态键发出查询。考虑修改您的架构以遵循更易于查询的文档模型:
// this operation changes the schema
var processed = [];
db.collection.find().forEach( function(doc) {
for(key in doc.processed) {
if(doc.processed.hasOwnProperty(key)) {
var item = { key: key, value: doc.processed[key] }
processed.push(item);
}
}
doc.processed = processed;
db.collection.save(doc);
});
// modified schema
{
"link": "xxxxx.jpg"
"_id": ObjectId("5501b1648ef0b4eccc41814e"),
"processed": [
{ "key": "320", "value": true },
{ "key": "480", "value": true },
{ "key": "540", "value": true },
{ "key": "720", "value": true },
{ "key": "800", "value": true },
{ "key": "1080", "value": true },
{ "key": "original", "value": false },
{ "key": "iPhone", "value": true }
]
}
您的查找查询将很简单
db.collection.find({"processed.value": false});
或使用 $map
和 $filter
到 return 具有 false
值的键作为
db.collection.aggregate([
{ "$project": {
"link": 1,
"notProcessed": {
"$map" : {
"input": {
"$filter": {
"input": "$processed",
"as": "el",
"cond": { "$not": "$$el.v" }
}
},
"in": "$$this.k"
}
}
} }
])
有了您在原始 post 中放入的文档架构,我们可以使用 Javascript 来;
- 查找所有记录
- 遍历
processed
对象
- 如果任何值等于布尔值
false
,将_id
添加到数组
- 打印
processed
对象中具有 false
值的 _id
查询到运行
var arrDoc = [];
db.test.find().forEach(
function anyFalse(doc) {
for(key in doc.processed) {
if(doc.processed.hasOwnProperty(key) && doc.processed[key] === false) {
arrDoc.push(doc._id);
break;
}
}
});
print( arrDoc.join("\r\n") );
示例文档
{
"_id" : ObjectId("5107de525ed6103609000016"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
}
}
示例输出
ObjectId("5107de525ed6103609000016")
补充说明
您可以将此javascript 函数anyFalse
存储到Mongo 中,并在需要时调用它。参见 store javascript function on server
编辑
如评论中所述,您有一个 images
数组。此函数将遍历所有 images
数组以检查子 processed
是否为假。
查询到运行
var arrDoc = [];
db.test.find().forEach(
function anyFalse(doc) {
var len = doc.images.length;
for( var i = 0; i < len; i++ ) {
for(key in doc.images[i].processed) {
if(doc.images[i].processed.hasOwnProperty(key) && doc.images[i].processed[key] === false) {
arrDoc.push(doc.images[i]._id);
break;
}
}
}
});
print( arrDoc.join("\r\n") );
示例文档
{
"_id" : ObjectId("5534fe2f3614af9afd23310a"),
"images" : [
{
"_id" : ObjectId("5107de525ed6103609000016"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : true,
"iPhone" : true
}
},
{
"_id" : ObjectId("5107de525ed6103609000017"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
}
}
]
}
我有一个包含以下对象的 Mongo 数据库:
[
{
"link" : "xxxxx.jpg"
"_id" : ObjectId("5501b1648ef0b4eccc41814e"),
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
}
}
]
我正在尝试查询任何处理过的值是假的,但我似乎无法弄清楚如何查询我不知道哪个键匹配的地方。这是否可以不循环遍历所有文档?
配合MongoDB3.4.4,使用聚合框架查询文档。这可以通过 $objectToArray
运算符实现,它允许您将已处理字段中的键映射到 key/value 对数组。该列表将很容易过滤并获得与您所拥有的任何条件相匹配的键。
在下面的示例中,聚合管道包含一个额外的字段,该字段包含与上述具有假值的条件相匹配的键,因此理想情况下它将是一个数组:
db.collection.aggregate([
{ "$addFields": {
"notProcessed": {
"$map" : {
"input": {
"$filter": {
"input": { "$objectToArray": "$processed" },
"as": "el",
"cond": { "$not": "$$el.v" }
}
},
"in": "$$this.k"
}
}
} }
])
产生
{
"_id" : ObjectId("5501b1648ef0b4eccc41814e"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
},
"notProcessed" : [
"original"
]
}
解释
从嵌套表达式开始
{
"$filter": {
"input": { "$objectToArray": "$processed" },
"as": "el",
"cond": { "$not": "$$el.v" }
}
}
$filter
operator { "$objectToArray": "$processed" }
的输入会将 processed
键中的键转换为这个数组:
[
{
"k" : "320",
"v" : true
},
{
"k" : "480",
"v" : true
},
{
"k" : "540",
"v" : true
},
{
"k" : "720",
"v" : true
},
{
"k" : "800",
"v" : true
},
{
"k" : "1080",
"v" : true
},
{
"k" : "original",
"v" : false
},
{
"k" : "iPhone",
"v" : true
}
]
和 $filter
将过滤上述数组以仅包含 v
属性 为 NOT
true
:
[
{
"k" : "original",
"v" : false
}
]
$map
将 return 一个仅包含值
[ { "k" : "original", "v" : false } ] => [ "original" ]
所以你最终只得到
[ "original" ]
结果。
对于较旧的 MongoDB 版本,将很难针对动态键发出查询。考虑修改您的架构以遵循更易于查询的文档模型:
// this operation changes the schema
var processed = [];
db.collection.find().forEach( function(doc) {
for(key in doc.processed) {
if(doc.processed.hasOwnProperty(key)) {
var item = { key: key, value: doc.processed[key] }
processed.push(item);
}
}
doc.processed = processed;
db.collection.save(doc);
});
// modified schema
{
"link": "xxxxx.jpg"
"_id": ObjectId("5501b1648ef0b4eccc41814e"),
"processed": [
{ "key": "320", "value": true },
{ "key": "480", "value": true },
{ "key": "540", "value": true },
{ "key": "720", "value": true },
{ "key": "800", "value": true },
{ "key": "1080", "value": true },
{ "key": "original", "value": false },
{ "key": "iPhone", "value": true }
]
}
您的查找查询将很简单
db.collection.find({"processed.value": false});
或使用 $map
和 $filter
到 return 具有 false
值的键作为
db.collection.aggregate([
{ "$project": {
"link": 1,
"notProcessed": {
"$map" : {
"input": {
"$filter": {
"input": "$processed",
"as": "el",
"cond": { "$not": "$$el.v" }
}
},
"in": "$$this.k"
}
}
} }
])
有了您在原始 post 中放入的文档架构,我们可以使用 Javascript 来;
- 查找所有记录
- 遍历
processed
对象 - 如果任何值等于布尔值
false
,将_id
添加到数组 - 打印
processed
对象中具有false
值的_id
查询到运行
var arrDoc = [];
db.test.find().forEach(
function anyFalse(doc) {
for(key in doc.processed) {
if(doc.processed.hasOwnProperty(key) && doc.processed[key] === false) {
arrDoc.push(doc._id);
break;
}
}
});
print( arrDoc.join("\r\n") );
示例文档
{
"_id" : ObjectId("5107de525ed6103609000016"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
}
}
示例输出
ObjectId("5107de525ed6103609000016")
补充说明
您可以将此javascript 函数anyFalse
存储到Mongo 中,并在需要时调用它。参见 store javascript function on server
编辑
如评论中所述,您有一个 images
数组。此函数将遍历所有 images
数组以检查子 processed
是否为假。
查询到运行
var arrDoc = [];
db.test.find().forEach(
function anyFalse(doc) {
var len = doc.images.length;
for( var i = 0; i < len; i++ ) {
for(key in doc.images[i].processed) {
if(doc.images[i].processed.hasOwnProperty(key) && doc.images[i].processed[key] === false) {
arrDoc.push(doc.images[i]._id);
break;
}
}
}
});
print( arrDoc.join("\r\n") );
示例文档
{
"_id" : ObjectId("5534fe2f3614af9afd23310a"),
"images" : [
{
"_id" : ObjectId("5107de525ed6103609000016"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : true,
"iPhone" : true
}
},
{
"_id" : ObjectId("5107de525ed6103609000017"),
"link" : "xxxxx.jpg",
"processed" : {
"320" : true,
"480" : true,
"540" : true,
"720" : true,
"800" : true,
"1080" : true,
"original" : false,
"iPhone" : true
}
}
]
}