查找所有文档,其中子集合中所有元素的特定字段包含在MongoDB / Mongoose中的给定数组内

使用MongoDB和Mongoose,比方说,我有这个模式:

var componentSchema = mongoose.Schema({ name : String, price : Number }); var partSchema = mongoose.Schema({ componentId : { type: Schema.Types.ObjectId, ref: 'Component' }, quantity : Number }); var robotSchema = mongoose.Schema({ name : String, type : Number, parts : [partSchema] }); 

每个机器人都需要一组要构build的组件。

由于机器人可能需要多于一个组件的副本(例如10个螺栓,5个螺钉,1个晶体pipe…),我们在机器人模型内部存储了一个部件数组,其中每个部件都包含对部件的引用,额外的领域 ,数量。

现在我感兴趣的是,给定一个组件的名字(或者最终给出一个componentIds数组)的数组,我可以使用这些types的组件创build所有的机器人(注意一个组件不包含数量,我只是假设我有一个无限量的那些组件),按照使用给定数组的大部分组件的顺序进行sorting。

 Robot A: 2 bolts, 2 transistors Robot B: 10 bolts, 2 capacitors, 3 bars of plutonium Robot C: 5 bolts, 1 capacitor, 5 transistors I have [bolts, capacitors, transistors]. Query results: Robot C Robot A (In this order!) 

是否可以用一个复杂的MongoDB查询?

当然。 您希望查找机器人文档,以便对于组件列表中的每个组件,信息中该组件的数量less于机器人文档中列出的数量,并且组件列表会耗尽机器人的组件列表。

 // robot docs { "name" : "My Fun Robot v3", "type" : 999, "parts" : [ { "_id" : 0, "quantity" : 2 }, { "_id" : 1, "quantity" : 5 }, { "_id" : 2, "quantity" : 1 }, { "_id" : 3, "quantity" : 7 } ] }, { "name" : "My Pun Robot v1", "type" : 222, "parts" : [ { "_id" : 4, "quantity" : 3 }, { "_id" : 1, "quantity" : 4 }, { "_id" : 2, "quantity" : 8 }, { "_id" : 6, "quantity" : 1 } ] }, { "name" : "My Sun Robot v876", "type" : 9834, "parts" : [ { "_id" : 0, "quantity" : 6 }, { "_id" : 1, "quantity" : 400 }, { "_id" : 2, "quantity" : 800 }, { "_id" : 3, "quantity" : 1000 } ] }, { "name" : "My Gun Robot v0", "type" : 1337, "parts" : [ { "_id" : 0, "quantity" : 1 }, { "_id" : 1, "quantity" : 1 }, { "_id" : 2, "quantity" : 1 }, ] } 

和组件信息

 \\ component info var components = [ { "_id" : 0, "quantity" : 20 }, { "_id" : 1, "quantity" : 20 }, { "_id" : 2, "quantity" : 20 }, { "_id" : 3, "quantity" : 20 }, { "_id" : 4, "quantity" : 20 } ] 

查询的构build:

 // for each component, we either need the component not to be required for the robot, or for the robot's quantity required to be less than the quantity we have var query = {} var comp_cond = [] components.forEach(function(comp) { comp_cond.push({ "$or" : [{ "parts" : { "$elemMatch" : { "_id" : comp._id, "quantity" : { "$lte" : comp.quantity } } } }, { "parts._id" : { "$ne" : comp._id } } ]}) }) query["$and"] = comp_cond // we need to make sure that there's no part in `parts` that's not in the components array query["parts"] = { "$not" : { "$elemMatch" : { "_id" : { "$nin" : components.map(function(comp) { return comp._id }) } } } } 

我不会显示上面的例子的实际查询,因为它真的很长。 您可以在mongo shell中运行代码并查看它。

 > db.robots.find(query, { "_id" : 0, "name" : 1 }) { "name" : "My Fun Robot v3" } { "name" : "My Gun Robot v0" } 

我相信这是正确的结果。 您应该进行更详尽的testing,以确保其处理组件列表可能无法匹配机器人部件列表的所有方式。