mongodb - nin & regex on an array - javascript

I have 2 collections, and I'm trying to get all records from Coll_A where a certain field (Field1) is not present in Coll_B.
The issue I'm running into is that this Field1 in Coll_A, which contains a string value, is padded at the end with white spaces up to a certain length, but this padding is absent in the other collection.
So, for the below query, the vals array has records that aren't padded, so when I use the db.Coll_A.find, it returns incorrect results.
vals = db.Coll_B.find({},
{"Field1" : 1, _id: 0})
.map(function(a){
return a.Field1;
});
db.Coll_A.find({ "Field1": { $nin: vals }});
How can I get around this? I looked up using regex for ignoring whitespaces, but I'm not sure how that can be used here. Any assistance would be really appreciated. Thanks.

You could simply, modify the return value to an array of regular expressions and use it in your $nin operator.
code:
var exp = db.Coll_B.find({}, {"Field1" : 1, _id: 0}).map(function(a){
return new RegExp(a.Field1+"\\s*$");
});
db.coll_A.find({"Field1":{$nin:exp}});
You cannot use $regex operator inside the $nin or $in operators.

I would suggest to fix inconsistent data in the collection. Update all the records with trimming white space around the field.
If for some reason you can't or don't want to do it, then you can use forEach and manually do the checking
var results = [];
db.Coll_A.find({}).forEach(function(row){
if(row.Field1.trim().indexOf(vals) === -1){
results.push(row);
}
});

Related

MongoDB javascript query; filter for value in in a column array

Using vanilla javascript, I'm using Mongo's dpd.js for querying the db.
In this snippet, I am trying find all matches for "design" in the column roleConsiderations within the collection techniques.
The values in roleConsiderations are in arrays - ["development", "design", "content"] and all of my different attempt to query for "design" fails.
dpd.js query results in empty response:
var query = {"roleConsiderations": "design"};
dpd.techniques.get(query, function (result) {
console.log(result);
});
Attempting to query through the url only returns exact matches (where "design" is the only value in the array).
http://my.mongo.db/techniques?roleConsiderations=["design"]
So how to query a mongodb column filtering for a value in an array?
You can use $in operator to specify the elements you want the returned objects to contain in specified field.
const query = { roleConsiderations: { $in: [ 'design' ] } };
Horrible syntax, I know, but it should work.
For more reading, please refer to this.

MongoDB search string in array of objects

I have a structure in MongoDB that have different amounts of items in an array called "items". To make the search, I am using the following command, which first turns the contents into a string, as in this.items there is a different structure depending on the object:
db.getCollection('docs').find.('JSON.stringify(this.items[0].value).toLowerCase().indexOf("text")!=-1')
My problem is that as I do not know the amount of items that each document has, I would have to use a wildcard as this.items[*].value, but it does not work.
Does anyone know any solution, or have another idea for this?
You can use the $elemMatch (https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/)
db.docs.find({items: {$elemMatch: {value: {$regex : "text"}}}});
So this query will find all documents with an item in the items array that contain the string "text" in the value property, after this operation you can count how much items the document has.
You can use dot notation of items.value to target the value field of all items elements, and a regular expression to perform the case-insensitive sub-string match:
db.getCollection('docs').find({ 'items.value': /text/i })
You can iterate each document and apply the indexOf, something like this..
var cursor = db.getCollection('docs').find({}); // get all docs
var newOut = []; // new array of items if match with some condition
while ( cursor.hasNext() ){ // iterate all docs
var doc = cursor.next(); // get the document in focus
doc.items.forEach(function(item){ // iterate the items of doc.items
if ( item.toLowerCase().indexOf("text") !== -1 ) // check if text exists in array
newOut.push(item); // add to new array
});
};
printjson(newOut);

Mongo get inverse of query

Hello I'm having trouble trying to understand how to write this query
My collection is a series of entries like this:
{
id:1,
name:"peter",
number:3
}
I want to be able to write a query which will return all items except for documents where the name='peter' and number=3
I know I can write something like:
db.test.find({$and:[{'name':'peter'},{'num':3}]})
to return all matching items, but is there any way of rewriting this query to return everything but the matching elements?
The $not operator requires a field to be bound to , but in this case it wont work.
Basically I had to rethink my query, using DeMorgan's law
¬(A^B) = ¬(A)V¬(B)
NOT (A AND B) = NOT(A) OR NOT(B)
so my query is
db.test.find({ $or:[{name:{$not:{$eq:'peter'}}},{num:{$not:{$eq:3}}}]});
Boolean algebra to the rescue!!
You can use a trick involving $nor with only one statement. Your only statement is then the original query. This works because $nor means that all conditions must be false; if you have only one condition, you get the negation.
So try:
db.test.find({$nor:[{$and:[{'name':'peter'},{'num':3}]}]})
I think this is nice because it's the negation of your original query exactly as it was
You can use the $ne operator to test for not equality:
find({$and: [{name: {$ne: peter}}, {num: {$ne: 2}}]})

How do I select a record by matching an index based on a partial string that contains '-' characters?

I'm using YDN-DB (an abstraction on top of IndexedDB) as a local database. I have an object store called 'conversations', and in that store, there's an index called 'participants' where there is a string containing id's for different users in the conversation. For example:
Example Conversation #1:
id: 1234343434353456,
participants: '171e66ca-207f-4ba9-8197-d1dac32499db,82be80e2-2831-4f7d-a8d7-9223a2d4d511'
Example Conversation #2:
id: 4321343434356543,
participants: 'd7fa26b3-4ecc-4f84-9271-e15843fcc83f,171e66ca-207f-4ba9-8197-d1dac32499db'
To try to perform a partial match on an index, I tried using ydn-db-fulltext as a solution. The full text catalog looks like this:
{
name: 'participants',
lang: 'en',
sources: [
{
storeName: 'conversations',
keyPath: 'participants',
weight: 1
}
]
}
I see that the catalog is generated, but there seems to be a problem doing exact matches. For example, if I query using only part of the key in the participants index, I get back a primary key from the catalog:
db.search('participants', 'd7fa26b3').done(function(results) {
if(results.length == 0) console.debug('No results found...');
console.debug(results); // there is 1 object here!
var primaryKey = results[0].primaryKey; // primaryKey exists!
});
However, when using any value past the '-', the search request returns 0 results:
db.search('participants', 'd7fa26b3-4ecc-4f84-9271-e15843fcc83f').done(function(results) {
if(results.length == 0) console.debug('No results found...');
console.debug(results); // there are 0 objects in the array
var primaryKey = results[0].primaryKey; // primaryKey throws undefined since there are 0 results!
});
This makes sense, when reading the documentation, in that '-' and '*' are reserved characters that remove a phrase and match a prefix respectively:
Query format is free text, in which implicit and/or/near logic operator apply for each token. Use double quote for exact match, - to subtract from the result and * for prefix search.
I tried putting double quotes inside the single quotes, using only double quotes, and also escaping all of the '-' characters with a backslash, but none of these seem to work.
So the question is how does one perform a match in an index where the string contains '-' characters?
Have you try db.search('participants', '"d7fa26b3"').
BTW, you are using full text search that is not suppose to do. You have to tokenize your string and index them manually.
If you store the participants field of your object as an array, then you can use the multi-entry flag to the createIndex method called on the participants field, and probably do what you want.
The number of items in the participants property of the object is mutable. When you update an object in the store and it has a different number of items in the partic property, then the index is automatically updated as a result (just like any other index). If you add an item to the prop, then restore (put/override/cursor.update) the object in the store, the index updates.
It helps to review the basics of how a multi-entry index works. You can do this with vanilla js, without a framework, and certainly without full-text searching.

regex and converting strings to array and back and forth Javascript

I am reading data from a text file and I am interested in a specific pattern that I have isolated with the following:
cleanString = queryString.match(/^NL.*/gm);
This results in the array:
["NL:What are the capitals of the states that border the most populated states?",
"NL:What are the capitals of states bordering New York?",
"NL:Show the state capitals and populations.",
"NL:Show the average of state populations.",
"NL:Show all platforms of Salute generated from NAIs with no go mobility."]
I then want to get rid of all patterns matching NL: so I am left with just a natural language question or statement. To accomplish this, I convert the array to a string , and then use .split() to create the desired array like so:
var nlString = cleanString.toString();
var finalArray = nlString.split(/NL:/gm);
There are two problems I am having.
1. I end up with an extra value of an empty string at index [0] in the resulting array, and
2. I now have a comma literal appended to the strings in the array:
["", "What are the capitals of the states that border the most populated states?,",
"What are the capitals of states bordering New York?,",
"Show the state capitals and populations.,",
"Show the average of state populations.,",
"Show all platforms of Salute generated from NAIs with no go mobility."]
How can I eliminate these problems? Also If someone has a more elegant approach to reading a big ugly text file delimited by line breaks and isolating strings of interest I am all eyes.
Thanks in advance for any suggestions.
You don't have to convert the array to a string, then remove the NL: strings and convert back to an array, just iterate over the array and remove that string in each index
var arr = arr.map(function(el) {return el.replace('NL:','');});
FIDDLE
a regular for loop would also work if older browsers is an issue
var finalString = nlString.replace(/NL:/gm, '');
Warning : map is not supported by IE8 and below. Here is an alternative :
var array = string.split(/\n*NL:/);
array.shift(); // that's it
Demo here : http://jsfiddle.net/wared/BYgLd/.

Categories