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
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:
http://docs.mongodb.org/manual/reference/operator/query/regex/
Retrieve only the queried element in an object array in MongoDB collection
Related
I have the below document.
I want to return "employeedata" containing only those array objects (family, academic etc.) for which status is "current"
{
"_id" : ObjectId("5a1fe7ed1e9fdd17285ac13f"),
"createdby" : "admin",
"details" : [
{
"_id" : ObjectId("5a1fe81f1e9fdd17285ac14a"),
"employeedata" : {
"createddate" : "2017-11-30T11:13:57.290Z",
"family" : [
{
"status" : "current",
"_id" : ObjectId("5a1fe81f1e9fdd17285ac153")
}
],
"academic" : [
{
"status" : "archive",
"_id" : ObjectId("5a1fe81f1e9fdd17285ac159")
},
{
"status" : "current",
"_id" : ObjectId("5a1fe8a71e9fdd17285ac15d")
}
],
"company" : [
{
"status" : "archive",
"_id" : ObjectId("5a1fe81f1e9fdd17285ac150")
},
{
"status" : "current",
"_id" : ObjectId("5a1fe88e1e9fdd17285ac15c")
}
],
"other" : [
{
"status" : "current",
"_id" : ObjectId("5a1fe81f1e9fdd17285ac154")
}
]
}
}
]
"confirmed" : true,
}
You can try following to filter the object as it is an complex object we will have to loop through the complete object and modify it at run time.
var data = JSON.parse('{"_id":"5a1fe7ed1e9fdd17285ac13f","createdby":"admin","details":[{"_id":"5a1fe81f1e9fdd17285ac14a","employeedata":{"createddate":"2017-11-30T11:13:57.290Z","family":[{"status":"current","_id":"5a1fe81f1e9fdd17285ac153"}],"academic":[{"status":"archive","_id":"5a1fe81f1e9fdd17285ac159"},{"status":"current","_id":"5a1fe8a71e9fdd17285ac15d"}],"company":[{"status":"archive","_id":"5a1fe81f1e9fdd17285ac150"},{"status":"current","_id":"5a1fe88e1e9fdd17285ac15c"}],"other":[{"status":"current","_id":"5a1fe81f1e9fdd17285ac154"}]}}]}');
function createObject() {
for (var obj in data.details[0].employeedata) {
if (Array.isArray(data.details[0].employeedata[obj])) {
data.details[0].employeedata[obj].filter(function (value, index) {
if (value.status !== 'current') {
//return value;
data.details[0].employeedata[obj].splice(index, 1);
}
})
}
}
}
I'm trying to make my mongodb collection searchable. I'm able to do text search after indexing a collection by text
db.products.createIndex({title: 'text'})
I'm wondering if it's possible to retrieve a list of all the index terms for this collection. This would be very useful for auto completion and spell checking/correction when people are writing their search queries.
There is no built in function for this in MongoDB. However, you can easily get this info with an aggregation query.
Let's assume that your collection contains the following documents:
{ "_id" : ObjectId("5874dbb1a1b342232b822827"), "title" : "title" }
{ "_id" : ObjectId("5874dbb8a1b342232b822828"), "title" : "new title" }
{ "_id" : ObjectId("5874dbbea1b342232b822829"), "title" : "hello world" }
{ "_id" : ObjectId("5874dbc6a1b342232b82282a"), "title" : "world title" }
{ "_id" : ObjectId("5874dbcaa1b342232b82282b"), "title" : "world meta" }
{ "_id" : ObjectId("5874dbcea1b342232b82282c"), "title" : "world meta title" }
{ "_id" : ObjectId("5874de7fa1b342232b82282e"), "title" : "something else" }
this query will give us the info on words :
db.products.aggregate([
{
$project:{
words:{
$split:["$title"," "]
}
}
},
{
$unwind:"$words"
},
{
$group:{
_id:"$words",
count:{
$sum:1
}
}
},
{
$sort:{
count:-1
}
}
])
This output the number of occurence for each word :
{ "_id" : "title", "count" : 4 }
{ "_id" : "world", "count" : 4 }
{ "_id" : "meta", "count" : 2 }
{ "_id" : "else", "count" : 1 }
{ "_id" : "something", "count" : 1 }
{ "_id" : "new", "count" : 1 }
{ "_id" : "hello", "count" : 1 }
If you are using MongoDB 3.4, you can get case insensitive / diacritic insensitive stats on the words with the new collation option.
for example, let's assume that our collection now contains the following documents:
{ "_id" : ObjectId("5874e057a1b342232b82282f"), "title" : "title" }
{ "_id" : ObjectId("5874e05ea1b342232b822830"), "title" : "new Title" }
{ "_id" : ObjectId("5874e067a1b342232b822831"), "title" : "hello world" }
{ "_id" : ObjectId("5874e076a1b342232b822832"), "title" : "World Title" }
{ "_id" : ObjectId("5874e085a1b342232b822833"), "title" : "World méta" }
{ "_id" : ObjectId("5874e08ea1b342232b822834"), "title" : "World meta title" }
{ "_id" : ObjectId("5874e0aea1b342232b822835"), "title" : "something else" }
add the collation option to the aggregation query :
db.products.aggregate([
{
$project:{
words:{
$split:["$title"," "]
}
}
},
{
$unwind:"$words"
},
{
$group:{
_id:"$words",
count:{
$sum:1
}
}
},
{
$sort:{
count:-1
}
}
],
{
collation:{
locale:"en_US",
strength:1
}
})
this will output:
{ "_id" : "title", "count" : 4 }
{ "_id" : "world", "count" : 4 }
{ "_id" : "méta", "count" : 2 }
{ "_id" : "else", "count" : 1 }
{ "_id" : "something", "count" : 1 }
{ "_id" : "new", "count" : 1 }
{ "_id" : "hello", "count" : 1 }
The strengh is the level of comparison to perform :
collation.strength: 1 // case insensitive + diacritic insensitive
collation.strength: 2 // case insensitive only
If we suppose autoCompleteTerm is your input value you can get the list of title using this query:
db.products.distinct('title', { $text: { $search: autoCompleteTerm } } )
Is db.products.distinct("title") , what you are looking for ?
I have the following collections in mongo:
> db.styles.find({ "_id" : "EP01L"}).pretty();
{
"_id" : "EP01L",
"__v" : 5,
"categoryIds" : [
ObjectId("5550dcc7a14c976741483c89"),
ObjectId("5550dcc7a14c976741483c8d")
],
"collectionId" : ObjectId("5550dab4a14c9766418ff2af"),
"colours" : {
"WH" : [
{
"on_sale" : false,
"size_code_id" : "S",
"sku" : "EP01L-WH1"
},
],
"BL" : [
{
"on_sale" : false,
"size_code_id" : "S",
"sku" : "EP01L-BL1"
},
]
},
"fabric" : {
"material" : [
{
"_id" : ObjectId("5550dab4a14c9766418ff2c4"),
"value" : 100
}
],
"type" : ObjectId("5550dab4a14c9766418ff2d1"),
"weight" : {
"ounce" : {
"min" : 4
},
"gram" : {
"min" : 155
}
}
},
"name" : {
"es-ES" : "CAMISETA MANGA LARGA HOMBRE",
"it-IT" : "T-SHIRT UOMO MANICA LUNGA",
"en-UK" : "MEN’S LONG SLEEVE T-SHIRT",
"fr-FR" : "T-SHIRT HOMME MANCHES LONGUES"
},
}
and
> db.attributes.find({"name.en-UK": "Fabric"}).pretty();
{
"_id" : ObjectId("5550dab4a14c9766418ff2dc"),
"values" : {
"source" : [
{
"code" : 1,
"_id" : ObjectId("5550dab4a14c9766418ff2bf"),
"name" : {
"fr-FR" : "Coton",
"it-IT" : "Cotone",
"en-UK" : "Cotton",
"es-ES" : "Algodón"
}
},
{
"code" : 2,
"_id" : ObjectId("5550dab4a14c9766418ff2c0"),
"name" : {
"fr-FR" : "Viscose",
"it-IT" : "Viscosa",
"en-UK" : "Viscose",
"es-ES" : "Viscosa"
}
},
],
"name" : [
{
"_id" : ObjectId("5550dab4a14c9766418ff2cd"),
"name" : {
"en-UK" : "3-ply Loopback"
}
},
{
"_id" : ObjectId("5550dab4a14c9766418ff2db"),
"name" : {
"en-UK" : "Woven Twill"
}
}
]
},
"name" : {
"en-UK" : "Fabric"
}
}
I am trying to write a query to find all the style documents that where fabric.source is either Cotton or Viscose and fabric.name is Woven Twill.
this query gives me all the documents that have fabric.type are Cotton or Viscose
> db.styles.find( { "fabric.type": { $in: [ ObjectId("5550dab4a14c9766418ff2cd"), ObjectId("5550dab4a14c9766418ff2db") ] } } ).count();
3
>
but how do I find all the styles where the size_code_id is S and colours is WH?
Please check the below query :
db.styles.find({
$and:[
{ "colours.WH" :{ $exists:1 } } ,
{ "colours.WH.size_code_id" : "S"}
]
}
).pretty();
If you need to find for "WH" and "BL", you can query like below :
db.styles.find({
$or:[
{
$and:[
{ "colours.WH" :{ $exists:1 } } ,
{ "colours.WH.size_code_id" : "S"}
]
},
{
$and:[
{ "colours.BL" :{ $exists:1 } } ,
{ "colours.BL.size_code_id" : "S"}
]
}
]
}
).pretty();
P.S : If you need to query for the multiple colors say for some 5- 10 different colours, Then you should construct the query dynamically for all those colors using JavaScript language constructs.
Below is the TESTED code for constructing the query dynamically :
// Colours you want to search
var varray = new Array("WH","BL");
var fname = "colours", lname = "size_code_id";
var arr = new Array();
var mquery = {"$or":[]};
for( var i = 0; i < varray.length; i++ )
{
var query = { "$and" : []};
// This line will dynamically construct a key as "colours.WH"
var s1 = fname.concat(".").concat(varray[i]);
// This line will dynamically construct a key as "colours.WH.size_code_id"
var s2 = fname.concat(".").concat(varray[i]).concat(".").concat(lname);
var sub1 = {}, sub2 = {};
sub1[s1] = { $exists:1 };
sub2[s2] = "S";
query["$and"].push(sub1);
query["$and"].push(sub2);
arr.push(query);
}
mquery["$or"] =arr;
db.styles.find(mquery);
i want to unset multiple object within array .. this is my db data
{
"_id" : ObjectId("5440e390fb038d3062000001"),
"firstname" : "demo2",
"contacts" : [
{
"contactId" : "544372d5f9ae85d0589d2b71",
"displayname" : "demo1",
"accounts" : {
"00e12ed769eb19239e218355cbe3c24f" : {
"type" : "mobile",
"userId" : "123456789",
"status" : 0,
}
}
},
{
"contactId" : "544372e4f9ae85d0589d2b72",
"displayname" : "demo2",
"accounts" : {
"00e12ed769eb19239e218355cbe3c24f" : {
"type" : "mobile",
"userId" : "123456789",
"status" : 0,
}
}
}
],
}
i used this db query but its updating only one record
db.users.update({'contacts.accounts.00e12ed769eb19239e218355cbe3c24f.userId':'123456789'},
{$unset:{'contacts.$.accounts.00e12ed769eb19239e218355cbe3c24f':''}},{multi:true})
Its updating only one but i want to update multiple items...
Just wrap your update statements in while like:
while (db.users.update({
'contacts.accounts.00e12ed769eb19239e218355cbe3c24f.userId' : '123456789'
}, {
$unset : {
'contacts.$.accounts.00e12ed769eb19239e218355cbe3c24f' : ''
}
}, {
multi : true
}).nMidified);
db.users.find({'contacts.accounts.00e12ed769eb19239e218355cbe3c24f.userId':'123456789'}).forEach(function(item)
{
var contacts = item.contacts;
for(var i = 0; i < contacts.length; i++)
{
var contact = contacts[i];
delete contact.accounts['00e12ed769eb19239e218355cbe3c24f'];
}
// db.users.save(item);
// use update() instead of save(
db.users.update({'contacts.accounts.00e12ed769eb19239e218355cbe3c24f.userId':'123456789'}, item);
})
I have a map-reduce query that "works" and does what I want however I have so far spectacularly failed to make use of my output data because I cannot workout how to read it back... let me explain... here is my emit:
emit( { jobid: this.job_id, type: this.type}, { count: 1 })
and the reduce function:
reduce: function (key, values) {
var total = 0;
for( i = 0; i < values.length; i++ ) {
total += values[i].count;
}
return { jobid: this.job_id, type:this.type, count: total};
},
It functions and the output I get in the results collection looks like this:
{ "_id" : { "jobid" : "5051ef142a120", "type" : 3 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051ef142a120", "type" : 5 }, "value" : { "count" : 43 } }
{ "_id" : { "jobid" : "5051f1a9d5442", "type" : 2 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051f1a9d5442", "type" : 3 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051f299340b1", "type" : 2 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051f299340b1", "type" : 3 }, "value" : { "count" : 1 } }
BUT HOW the hell do I issue a query that says find me all jobid entries by "jobid" whilst ignoring the type? I tried this intiailly, expecting two rows of output but got none!
db.mrtest.find( { "_id": { "jobid" : "5051f299340b1" }} );
I have also tried and failed with:
db.mrtest.find( { "_id": { "jobid" : "5051f299340b1" }} );
and whilst:
db.mrtest.find( { "_id" : { "jobid" : "5051f299340b1", "type" : 2 }} )
does produce one row of output as hoped for, changing it to this again fails to produce anything:
db.mrtest.find( { "_id" : { "jobid" : "5051f299340b1", "type" : { $in: [2] }}} )
I get the impression that you can't do such things with the _id field, or can you? I am thinking I need to re-organise my mr output instead but that feels like failing somehow ?!?!
Help!
PS: If anybody can explain why the count is contained in a field called "value", that would also be welcome!"5051f299340b1"
Have you tried:
db.mrtest.find( { "_id.jobid": "506ea3a85e126" })
That works for me!
db.mrtest.find( { "_id.jobid": "506ea3a85e126" })