1

I need some guidence in a query for mongodb. I have a collection of items which contain an array that contains multiple fields, but I only care about one field, which is the barcode field. I need to distiguish the length of the barcode string.

Items.find({this.array['barcode'].length > 6})  

It would be great if the above query was possible, but I believe that it's not. I only need a list of barcodes. How do I go about solving this problem? Does mongodb have something to compare length of a string? Or do I have to use a mapReduce query? If I do could I have some guidence on that? I'm not sure how I would go about writing it.
Thank you

raging_subs
  • 839
  • 2
  • 11
  • 27

1 Answers1

0

Try using a regular expression. /^\w{6}/ this says match a word that has 6 word characters at the start of the string.

Example:

Setup:

user test;
var createProduct = function(name, barcode){
  return {
    name : name,
    detail: {
      barcode : barcode
    }
  };
};
db.products.drop();
for(var i = 0; i < 10; i++){
  db.products.insert( createProduct( "product" + i, "1234567890".substring(0,i+1) ));
}

Document structure:

{
    "_id" : ObjectId("540d3ba1242ff352caa6154b"),
    "name" : "product0",
    "detail" : {
        "barcode" : "1"
    }
}

Query:

db.products.find({ "detail.barcode" : /^\w{6}/ })

Output:

{ "_id" : ObjectId("540d3ba1242ff352caa61550"), "name" : "product5", "detail" : { "barcode" : "123456" } }
{ "_id" : ObjectId("540d3ba1242ff352caa61551"), "name" : "product6", "detail" : { "barcode" : "1234567" } }
{ "_id" : ObjectId("540d3ba1242ff352caa61552"), "name" : "product7", "detail" : { "barcode" : "12345678" } }
{ "_id" : ObjectId("540d3ba1242ff352caa61553"), "name" : "product8", "detail" : { "barcode" : "123456789" } }
{ "_id" : ObjectId("540d3ba1242ff352caa61554"), "name" : "product9", "detail" : { "barcode" : "1234567890" } }

However, if barcode is a key within an object inside an array AND you only want the matched barcode values. Then you should use an aggregate function to extract the values.

Setup:

user test;
var createProduct = function(name){
  var o = {
    name : name,
    subProducts: []
  };
  for(var i = 0; i < 10; i++){
    o.subProducts.push({
      barcode : "1234567890".substring(0,i+1)
    });
  }
  return o;
};
db.products.drop();
db.products.insert( createProduct( "newBrand") );

Document Structure:

{
    "_id" : ObjectId("540d4125242ff352caa61555"),
    "name" : "newBrand",
    "subProducts" : [
        {
            "barcode" : "1"
        },
...
        {
            "barcode" : "123456789"
        },
        {
            "barcode" : "1234567890"
        }
    ]
}

Aggregate Query:

db.products.aggregate([
  { $unwind : "$subProducts" },
  { $match : { "subProducts.barcode" : /^\w{6}/ } }
]);

Output:

{ "_id" : ObjectId("540d4125242ff352caa61555"), "name" : "newBrand", "subProducts" : { "barcode" : "123456" } }
{ "_id" : ObjectId("540d4125242ff352caa61555"), "name" : "newBrand", "subProducts" : { "barcode" : "1234567" } }
{ "_id" : ObjectId("540d4125242ff352caa61555"), "name" : "newBrand", "subProducts" : { "barcode" : "12345678" } }
{ "_id" : ObjectId("540d4125242ff352caa61555"), "name" : "newBrand", "subProducts" : { "barcode" : "123456789" } }
{ "_id" : ObjectId("540d4125242ff352caa61555"), "name" : "newBrand", "subProducts" : { "barcode" : "1234567890" } }

More info:

Community
  • 1
  • 1
Larry Battle
  • 8,222
  • 4
  • 39
  • 54
  • Thanks Larry, I had troubles with your regex so I just changed mine to { $match : { "barcode" : /^.{0,6}$/ } } – raging_subs Sep 08 '14 at 14:10
  • So I got the result of [ 0:{ _id: }, 1:{ _id: } ... ]. Is there anyway to change this to be just an array of barcodes? ie) [, ...] Here is my updated query. db.Items.aggregate([ { $unwind : "$item" }, { $match : { "item.barcode" : /^.{0,6}$/ }, { $project: { "item.barcode" : 1, "_id":0 } }, { $group : { "_id" : "$item.barcode"} }, { $limit : 100 } ]) – raging_subs Sep 08 '14 at 15:11
  • @raging_sub Please update your question with a sample document. – Larry Battle Sep 08 '14 at 15:55