Remember, MongoDB has a dynamic schema. So it is perfectly ok to store this document:
{
"JobNumber" : "50001-01",
"CustomerId" : "joe",
"IdentifierNumber" : NumberLong(8812739),
"TimesPrinted" : 0,
"Packaging" : {"bundle":1200,"box":120,"pallet":3}
}
and this document
{
"JobNumber" : "50001-02",
"CustomerId" : "jane",
"IdentifierNumber" : NumberLong(8812739),
"TimesPrinted" : 0,
"Packaging" : {"sack":200}
}
in the same collection.
Since, I wouldn't query for the Nth document, but for a given field in the subdocument, for example
db.collection.find({"packaging.bundle":1200})
which would run just fine with MongoDB. The reason behind that is that if a field isn't present in a document, it is evaluated as null
for a query. And null
is definitely not equal to 1200.
As for the performance. It really depends on who big your collection is and how your queries look like. While the query as shown above may be rather slow in a collection containing hundred of thousands of documents (or even more) without an index, it can be extremely fast when you created an index on it, e.g.
db.collection.ensureIndex({"packaging.bundle":1,"packaging.box":1,"packaging.pallet":1});
If you can create an index like this obviously depends on the question wether you really have arbitrary packaging or if you simply have a variety of packaging options. If the latter is the case, I'd create an index for each of the packaging options, utilizing sparse indices, e.g.
db.collection.ensureIndex({"packaging.sack":1},{sparse:true})
This would reduce the index size, as only documents which hold the field "packaging.sack" would be contained in this index.
If you really have arbitrary fields in the documents, I wonder how you create a model for it ;)
When talking of just some ten thousands of documents, you might even get satisfying result without an index.
Best Answer
Depending on your version of MongoDB server there are a few ways to approach this.
In MongoDB 3.6+ you can use the
$setIsSubset
expression (which istrue
only when the first array given is a subset of the second) via the$expr
operator:For earlier versions of MongoDB a similar outcome is possible (but less obvious) using double negation with the
$elemMatch
operator:Roughly translated: "find all documents where it is not the case that the
vals
array includes a value other than one in the provided list".