组合多个数组以使用 MongoDB Java 驱动程序进行查询
Combining multiple arrays for querying with MongoDB Java driver
我有以下 JSON:
{"pid":"b00l16vp","categories":{"category1":["factual", "arts culture and the media", "history"]}}
{"pid":"b0079mpp","categories":{"category2":["childrens", "entertainment and comedy", "animation"],"category1":["signed"]}}
{“pid":"b00htbn3"}
{“pid":"b00gdhqw","categories":{"category2":["factual"],"category3":["scotland"],"category4":["lifestyle and leisure", "food and drink"],"category1":["entertainment", "games and quizzes"]}}
我的目的是通过将所有数组合并到一个数组中来使用字符串数组查询类别对象。
我有以下代码:
String [] cats = ["childrens", "signed"]
BasicDBObject theProjections = new BasicDBObject()
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i
String cleanIdentifier = "$" + identifier
//If the category does not exist, put in a blank category
def temp = [cleanIdentifier, []]
theMegaArray.add(new BasicDBObject('$ifNull', temp))
}
//The megaArray is the array created in the above loop which combines all arrays
BasicDBObject theData = new BasicDBObject('$setUnion', theMegaArray)
BasicDBObject theFilter = new BasicDBObject('input', theData)
theFilter.put("as", "megaArray")
//all of the values found in cats should match the megaArray
theFilter.put("cond", new BasicDBObject('$all', ["$$megaArray", cats]))
theProjections.put('$filter', theFilter)
FindIterable iterable = collection.find(criteria).projection(theProjections)
我用过 question to come to write this code so far. The $setUnion expects all of the fields to appear however in my JSON, there are a varied number of categrories arrays hence I have used the $ifNull to populate empty categories with []. The $filter 已经用过在megaArray上查询cats数组。
当 运行 出现以下错误时:
Caused by: com.mongodb.MongoQueryException: Query failed with error code 2 and error message '>1 field in obj: { input: { $setUnion: [ { $ifNull: [ "$categories.category1", [] ] }, { $ifNull: [ "$categories.category2", [] ] }, { $ifNull: [ "$categories.category3", [] ] }, { $ifNull: [ "$categories.category4", [] ] }, { $ifNull: [ "$categories.category5", [] ] } ] }, as: "megaArray", cond: { $all: [ "$$megaArray", [ "factual" ] ] } }'
我不完全确定这看起来是什么意思。我还应该注意到类别对象并不总是存在,但我不确定这是否重要。
您可以使用聚合框架实现相同的结果
为此,您可以先投影数据以创建 'megaArray',然后匹配新数组。
String [] cats = new String[] {"childrens", "signed"};
List<DBObject> theMegaArray = new ArrayList<>();
BasicDBObject theProjections = new BasicDBObject();
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i;
String cleanIdentifier = "$" + identifier;
//If the category does not exist, put in a blank category
Object[] temp = new Object[] {cleanIdentifier, new Object[]{}};
theMegaArray.add(new BasicDBObject("$ifNull", temp));
}
theProjections.put("_id", 1);
theProjections.put("pid", 1);
theProjections.put("categories",1);
theProjections.put("allCategories", new BasicDBObject("$setUnion", theMegaArray));
BasicDBObject theFilter = new BasicDBObject("allCategories", new BasicDBObject("$all", cats));
List<BasicDBObject> pipeline = new ArrayList<>();
pipeline.add(new BasicDBObject("$project", theProjections));
pipeline.add(new BasicDBObject("$match", theFilter));
AggregateIterable iterable = collection.aggregate(pipeline);
上面的代码示例在项目阶段添加了一个名为 "allCategories" 的新数组,然后与这个新文档进行匹配。
可以添加另一个投影阶段以从最终输出中删除 allCategories 数组
您可以使用以下聚合管道。
Shell查询参考:
db.collection.aggregate([{
"$project": {
"pid": 1,
"categories": 1,
"filter": {
"$eq": [{
"$setUnion": [{
"$ifNull": ["$categories.category1", []]
}, {
"$ifNull": ["$categories.category2", []]
}, {
"$ifNull": ["$categories.category3", []]
}, {
"$ifNull": ["$categories.category4", []]
}, {
"$ifNull": ["$categories.category5", []]
}]
},
["childrens", "signed"]
]
}
}
}, {
"$match": {
"filter": true
}
}])
Java代码:
String[] cats = {"childrens", "signed"};
// Combining the optional categories arrays
BasicDBList theMegaArray = new BasicDBList();
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i;
String cleanIdentifier = "$" + identifier;
theMegaArray.add(new BasicDBObject("$ifNull", Arrays.asList(cleanIdentifier, Collections.EMPTY_LIST)));
}
BasicDBObject theData = new BasicDBObject("$setUnion", theMegaArray);
// Add equals filter - Compare the arrays and output boolean filter field
BasicDBObject theFilter = new BasicDBObject("$eq", Arrays.asList(theData, cats));
// Add projections to keep the output fields
BasicDBObject theProjections = new BasicDBObject();
theProjections.put("filter", theFilter);
theProjections.put("pid", 1);
theProjections.put("categories", 1);
// Add $project stage
BasicDBObject theProject = new BasicDBObject("$project", theProjections);
// Add $match stage to compare the boolean filter field to true to keep matching documents
BasicDBObject theMatch = new BasicDBObject("$match", new BasicDBObject("filter", true));
// Add stages to piepline
BasicDBList pipeline = new BasicDBList();
pipeline.add(theProject);
pipeline.add(theMatch);
// Run aggregation
AggregateIterable iterable = collection.aggregate(pipeline);
我有以下 JSON:
{"pid":"b00l16vp","categories":{"category1":["factual", "arts culture and the media", "history"]}}
{"pid":"b0079mpp","categories":{"category2":["childrens", "entertainment and comedy", "animation"],"category1":["signed"]}}
{“pid":"b00htbn3"}
{“pid":"b00gdhqw","categories":{"category2":["factual"],"category3":["scotland"],"category4":["lifestyle and leisure", "food and drink"],"category1":["entertainment", "games and quizzes"]}}
我的目的是通过将所有数组合并到一个数组中来使用字符串数组查询类别对象。 我有以下代码:
String [] cats = ["childrens", "signed"]
BasicDBObject theProjections = new BasicDBObject()
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i
String cleanIdentifier = "$" + identifier
//If the category does not exist, put in a blank category
def temp = [cleanIdentifier, []]
theMegaArray.add(new BasicDBObject('$ifNull', temp))
}
//The megaArray is the array created in the above loop which combines all arrays
BasicDBObject theData = new BasicDBObject('$setUnion', theMegaArray)
BasicDBObject theFilter = new BasicDBObject('input', theData)
theFilter.put("as", "megaArray")
//all of the values found in cats should match the megaArray
theFilter.put("cond", new BasicDBObject('$all', ["$$megaArray", cats]))
theProjections.put('$filter', theFilter)
FindIterable iterable = collection.find(criteria).projection(theProjections)
我用过
当 运行 出现以下错误时:
Caused by: com.mongodb.MongoQueryException: Query failed with error code 2 and error message '>1 field in obj: { input: { $setUnion: [ { $ifNull: [ "$categories.category1", [] ] }, { $ifNull: [ "$categories.category2", [] ] }, { $ifNull: [ "$categories.category3", [] ] }, { $ifNull: [ "$categories.category4", [] ] }, { $ifNull: [ "$categories.category5", [] ] } ] }, as: "megaArray", cond: { $all: [ "$$megaArray", [ "factual" ] ] } }'
我不完全确定这看起来是什么意思。我还应该注意到类别对象并不总是存在,但我不确定这是否重要。
您可以使用聚合框架实现相同的结果
为此,您可以先投影数据以创建 'megaArray',然后匹配新数组。
String [] cats = new String[] {"childrens", "signed"};
List<DBObject> theMegaArray = new ArrayList<>();
BasicDBObject theProjections = new BasicDBObject();
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i;
String cleanIdentifier = "$" + identifier;
//If the category does not exist, put in a blank category
Object[] temp = new Object[] {cleanIdentifier, new Object[]{}};
theMegaArray.add(new BasicDBObject("$ifNull", temp));
}
theProjections.put("_id", 1);
theProjections.put("pid", 1);
theProjections.put("categories",1);
theProjections.put("allCategories", new BasicDBObject("$setUnion", theMegaArray));
BasicDBObject theFilter = new BasicDBObject("allCategories", new BasicDBObject("$all", cats));
List<BasicDBObject> pipeline = new ArrayList<>();
pipeline.add(new BasicDBObject("$project", theProjections));
pipeline.add(new BasicDBObject("$match", theFilter));
AggregateIterable iterable = collection.aggregate(pipeline);
上面的代码示例在项目阶段添加了一个名为 "allCategories" 的新数组,然后与这个新文档进行匹配。
可以添加另一个投影阶段以从最终输出中删除 allCategories 数组
您可以使用以下聚合管道。
Shell查询参考:
db.collection.aggregate([{
"$project": {
"pid": 1,
"categories": 1,
"filter": {
"$eq": [{
"$setUnion": [{
"$ifNull": ["$categories.category1", []]
}, {
"$ifNull": ["$categories.category2", []]
}, {
"$ifNull": ["$categories.category3", []]
}, {
"$ifNull": ["$categories.category4", []]
}, {
"$ifNull": ["$categories.category5", []]
}]
},
["childrens", "signed"]
]
}
}
}, {
"$match": {
"filter": true
}
}])
Java代码:
String[] cats = {"childrens", "signed"};
// Combining the optional categories arrays
BasicDBList theMegaArray = new BasicDBList();
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i;
String cleanIdentifier = "$" + identifier;
theMegaArray.add(new BasicDBObject("$ifNull", Arrays.asList(cleanIdentifier, Collections.EMPTY_LIST)));
}
BasicDBObject theData = new BasicDBObject("$setUnion", theMegaArray);
// Add equals filter - Compare the arrays and output boolean filter field
BasicDBObject theFilter = new BasicDBObject("$eq", Arrays.asList(theData, cats));
// Add projections to keep the output fields
BasicDBObject theProjections = new BasicDBObject();
theProjections.put("filter", theFilter);
theProjections.put("pid", 1);
theProjections.put("categories", 1);
// Add $project stage
BasicDBObject theProject = new BasicDBObject("$project", theProjections);
// Add $match stage to compare the boolean filter field to true to keep matching documents
BasicDBObject theMatch = new BasicDBObject("$match", new BasicDBObject("filter", true));
// Add stages to piepline
BasicDBList pipeline = new BasicDBList();
pipeline.add(theProject);
pipeline.add(theMatch);
// Run aggregation
AggregateIterable iterable = collection.aggregate(pipeline);