我有一个json文档,像这样:
{
"A": [
{
"C": "abc",
"D": "de"
},
{
"C": "fg",
"D": "hi"
}
]
}
我将检查"A"是否包含字符串ef。首先连接所有值abcdefghi,然后搜索ef在XML中,XPATH应该是这样的://A[contains(., 'ef')]
在Mongodb中是否有类似的查询?
对于这种类型的搜索,所有选项都非常糟糕,但是您可以采用一些方法。请注意,虽然这里的结束情况可能是最好的解决方案,但我提出的选项是为了说明问题。
如果数组"A"中的键是一致定义的,并且总是包含数组,那么您将像这样搜索:
db.collection.aggregate([
// Filter the documents containing your parts
{ "$match": {
"$and": [
{ "$or": [
{ "A.C": /e/ },
{ "A.D": /e/ }
]},
{"$or": [
{ "A.C": /f/ },
{ "A.D": /f/ }
]}
]
}},
// Keep the original form and a copy of the array
{ "$project": {
"_id": {
"_id": "$_id",
"A": "$A"
},
"A": 1
}},
// Unwind the array
{ "$unwind": "$A" },
// Join the two fields and push to a single array
{ "$group": {
"_id": "$_id",
"joined": { "$push": {
"$concat": [ "$A.C", "$A.D" ]
}}
}},
// Copy the array
{ "$project": {
"C": "$joined",
"D": "$joined"
}},
// Unwind both arrays
{ "$unwind": "$C" },
{ "$unwind": "$D" },
// Join the copies and test if they are the same
{ "$project": {
"joined": { "$concat": [ "$C", "$D" ] },
"same": { "$eq": [ "$C", "$D" ] },
}},
// Discard the "same" elements and search for the required string
{ "$match": {
"same": false,
"joined": { "$regex": "ef" }
}},
// Project the origial form of the matching documents
{ "$project": {
"_id": "$_id._id",
"A": "$_id.A"
}}
])
因此,除了可怕的 $regex
匹配之外,为了使字段"连接"以便再次按顺序搜索字符串,还有一些需要经过的环节。还要注意这里可能的反向连接可能产生假阳性。目前还没有简单的方法来避免反向连接或过滤它,因此需要考虑这个问题。
另一种方法基本上是通过任意JavaScript运行所有内容。mapReduce方法可以成为您实现这一点的工具。在这里,您可以稍微放宽可以包含在" a "和try中的数据类型,将更多的条件匹配与try结合起来,以减少您正在处理的文档集:
db.collection.mapReduce(
function () {
var joined = "";
if ( Object.prototype.toString.call( this.A ) === '[object Array]' ) {
this.A.forEach(function(doc) {
for ( var k in doc ) {
joined += doc[k];
}
});
} else {
joined = this.A; // presuming this is just a string
}
var id = this._id;
delete this["_id"];
if ( joined.match(/ef/) )
emit( id, this );
},
function(){}, // will not reduce
{
"query": {
"$or": [
{ "A": /ef/ },
{ "$and": [
{ "$or": [
{ "A.C": /e/ },
{ "A.D": /e/ }
]},
{"$or": [
{ "A.C": /f/ },
{ "A.D": /f/ }
]}
] }
]
},
"out": { "inline": 1 }
}
);
所以你可以使用任意逻辑来搜索包含的对象。这个只是区分了"数组"和假设是字符串,允许查询的附加部分首先搜索匹配的"string"元素,这是一个"短路"计算。
但是在一天结束的时候,最好的方法是简单地将数据呈现在文档中,并且在更新文档内容时必须自己维护它:
{
"A": [
{
"C": "abc",
"D": "de"
},
{
"C": "fg",
"D": "hi"
}
],
"search": "abcdefghi"
}
因此,这仍然会调用 $regex
类型查询的可怕用法,但至少这避免了(或者更确切地说,转移到编写文档)"连接"元素的开销,以影响搜索所需的字符串。
这最终导致的是一个"完全成熟"的文本搜索解决方案,这意味着一个外部的一个在这个时候,而不是MongoDB的文本搜索设施,可能会是你最好的性能选择。
在创建"连接"字段时使用"预存储"方法,或者在支持的情况下(Solr是可以做到这一点的一种解决方案),在索引文档内容时创建文本索引中的"计算字段"。
无论如何,这些都是解决问题的方法和要点。这不是XPath搜索,也不是从这个意义上看整个集合的某种"类似XPath"的视图,因此您最适合按照能够提供最佳性能的方法构建数据。
说了这么多,这里的示例是一个相当人为的示例,如果您有一个"像"这样的东西的实际用例,那么实际用例可能会产生一个非常有趣的问题。实际案例的解决方案通常与虚构案例不同。但是现在你有事情要考虑了。