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);
Related
I have the following structure, either a single string array ['stufff sjktasjtjser ((matchthis))'], or the same structure in a nested array ['stufff', ['more stuff ((matchhere))'], '((andanother))'];
I can loop and match all regex in the brackets and even replace the text:
//after flattening the array lets take the first one, assume I am looping in the first element.
var matches = currentArrayElement.matchAll('fancyregex') //pretend I am matching the brackets
matchs.forEach(match=>currentArrayElement=currentArrayElement.replaceAll(match[0],'whatwhat'))
console.log(currentArrayElement)//'stufff sjktasjtjser whatwhat'
//but what I actually want is
// currentArrayElement = ['stufff sjktasjtjser','whatwhat'];
Does anyone knows how I can achieve that? Or any template lib that can do that within nested arrays? I need to output sometimes an array of a string ['tss'] and sometimes an array with an object [{}].
Thanks.
The issue was that I needed to change the array in that index not the entire array.
Here is what I did then:
//after flattening the array lets take the first one, assume I am looping in the first element.
var matches = currentArrayElement.matchAll('fancyregex') //pretend I am matching the brackets
matches.forEach((match) => {
currentArrayElement[i] = c.split(match[0]).flatMap(
(value, index, array) => (array.length - 1 !== index
? [value, 'whatwhat',]
: value),
);
});
From the name of the question this might seem like an easy task, but im a beginner. What I need to do is compare a string (user input, I already have it), with a list of words. Basically if the user inputs bluuexel I still want to have the program to interpret it as blue (im actually making a bot to censor words and just entering random stuff is a common strategy to bypass censors). I was going to sort and delete duplicates but then I realized that "ass" would become "as" and this strategy wouldnt be as applicable.
For analyzing strings, you may use String.prototype.includes to see if a substring is located in a string or other options such as Regex for exact matches. Many approaches may be applied, but this example may get you started. String.prototype.includes
For replacing other strings, you something such as String.prototype.replace. String.prototype.replace
Since you also tagged this post under Node.js, to receive user input from the command prompt. Use may use the Node.js readline module. Readline
Beware of the comparison item.value == search may cause unexpected type coercion also. That is why we are using ====.
Note
Your question is a little broad, but it seems you are trying to compare strings against other strings. It would help to provide some code so we get a sense of what you are trying to accomplish.
var items = [{
value: "one"
},
{
value: "bluuexel"
}
]
// Accept a search string term variable
unique = (search) => {
// Iterate through the object items
// Some: Determines whether the specified callback function
// returns true for any element of an array.
return items.some(item => {
// Return if item.value is equal to the search string, beware of
// Comparison item.value == search may cause unexpected type
// coercion. So we use ===
return item.value === search
});
};
// Accept a search string term variable
contains = (search) => {
// Iterate through the object items
// Some: Determines whether the specified callback function
// returns true for any element of an array.
return items.some(item => {
// Includes: Returns true if searchString
// appears as a substring of the result of converting
// this object to a String, at one or more positions that
// are greater than or equal to position; otherwise, returns false.
// Return if item.value contains equal to the search string
return item.value.includes(search)
});
};
console.log('Unique:', unique('bluuexel'), '=> bluuexel');
console.log('Contains:', contains('bluu'), '=> bluu');
console.log('Contains:', contains('bluu2'), '=> bluu2');
console.log('Unique:', unique('one'), '=> one');
console.log('Unique:', unique('one2'), '=> one2');
Now for removing words from an array or duplicates, also many other approaches. But here is a simple example.
We also make use of the Spread syntax (...) allows an iterable such as an array expression or string to be expanded in short terms. Spread
The Set constructor lets you create Set objects that store unique values of any type, whether primitive values or object references. Set
// Defined list of an array of words
let words = ['bluuexel', 'bluuexel2', 'bluuexel'];
// ... Spread operator to iterate over array elements in array "words"
console.log('Removed (Duplicates)', words);
let removed = [...new Set(words)];
// Output unique only words, from new array named "removed"
console.log('Removed (Non Duplicates)', removed);
Putting it together to remove some banned words and also duplicates.
// Filtering words and duplicates
// Word List
let words = [ 'one',
'one',
'two',
'two2',
'ass',
'as']
// Banned Words
let banned = ['ass']
// Contains word, accepts a string and a list as an array
contains = (search, list) => {
// Determine if the list has a string
return list.some(item => {
return item.includes(search)
});
};
// Function for filtering, and removing duplicates and banned words
function filter() {
// Remove duplicates first, update word list
words = [...new Set(words)];
// Iterate through banned word list
banned.forEach((word) => {
// Output that banned word was found
console.log('Found Banned (Word):', word)
if (contains(word, words)) {
// Update final word list
words.splice(words.indexOf(word), 1);
}
})
}
console.log('Previous Results', words)
// Run filter function
filter()
// Output results
console.log('Final Results', words)
I'm currently using a method to try to filter some arrays, the method is almost working but I can't seem to access the exact values -
I make a call and add each returned array into a bigger array, these arrays will then be assigned a productId and maybe some data, i am appending the productIds using this:
data.push({'productId': product.id});
Which unfortunately adds a new object to the array which means my function below doesnt work unless the productId is in the first object of each array:
let matchedArray = data.flatMap(arr => arr.filter(obj => obj.productId == id))
What I need to do is filter the array down to the subarray that matches the productId and ID and also that has some of the fields of data such as 'name' - so it checks that the name isnt empty.
The data set looks like this (array of subarrays)
id = 12345
data = [[],[],[],[],[],[],[],[],[{"id":"123","name":"africa soul
2019","startDate":null,"endDate":null,"country":null,"city":null,"type":"Ev
ent","members":null},{"productId":"12345"}],[],[],[],[],[],[],
[],[],[],[],[]]
As you can see the productId is appended to the array but isnt now working with my filter method, i need to filter for the right array that has matching ID's and at least one of the fields are also existing. I either need to change the way the productId is manually appended, or change the filter method?
Thanks so much if you can help
If you want to filter all the arrays which have some object which have a productId equal to a given value:
let data = [[],[],[],[],[],[],[],[],[{"id":"123","name":"africa soul 2019","startDate":null,"endDate":null,"country":null,"city":null,"type":"Event","members":null},{"productId":"12345"}],[],[],[],[],[],[],[],[],[],[],[]],
id = "12345";
let filtered = data.filter(arr => arr.some(a => a.productId === id))
console.log(filtered)
If you want to get the first match, use find instead of filter
It's quite possible I am going about this the wrong way, but I have a primary array that i need to filter if any of it's objects values exist in two other arrays. I am trying to use a combination of filter() and some() but what I have right now is not working.
const milestones = <FormArray>this.piForm.get('_milestones');
if (this.piById) {
milestonesToCreate = milestones.value
.filter(milestone => !this.piById.milestones.some(item => item.milestoneId === milestone.milestoneId));
milestonesToDelete = this.piById.milestones
.filter(milestone => !milestones.value.some(item => item.milestoneId === milestone.milestoneId));
milestonesToUpdate = milestones.value
.filter(milestone => milestones.value
.some(item =>
item.milestoneId === milestonesToCreate.milestoneId && milestonesToDelete.milestoneId));
}
In the code above milestonesToUpdate should be a the filtered results where the array consists of objects that are not in milestonesToCreate and milestonesToDelete
Hopefully I've explained this well enough.
ADDED SAMPLE MILESTONES ARRAY
milestones = [
{
"milestoneId": 0
}
]
Firstly, it looks like your problem is just a misunderstanding of boolean checks in your final call to some().
You have put:
item.milestoneId === milestonesToCreate.milestoneId && milestonesToDelete.milestoneId
Which is the same as saying, where item.milestoneId equals milestonesToCreate.milestoneId AND milestonesToDelete.milestoneId exists. I expect that you are just trying to check if the current value exists in both arrays.
it's better to achieve that in single pass:
put all elements to elementsToUpdate, copy all elements from your this into elementsToDelete
iterate through elementsToUpdate, once some item does not exist in another list, move that element into elementsToCreate
if element exists in both, remove it from elementsToDelete.
finally you will get 3 lists you need.
And you can even speed up code more if instead of using arrays you use hash(old good {}) where id are used as keys. Then check "if element is here" would be as easy as item in elementsToUpdate instead of iterating all the elements each time
I've a little array problem I'm going round and round in loops with.
I have a number of check boxes, each checkbox has a specific object.
On checking a checkbox I want to iterate over the array and if the id of the checkbox (object) does not match any other items in the array, push to the array.
I have the following, which pushes the checkbox object for every item that doesn't match it's id. So I end up with multiple objects of the same ID.
mapMarkers.map(marker => {
if(markerID !== marker[0].id) {
mapMarkers.push(markerObject)
};
});
Any help to get my thinking on this straight would be appreciated.
For context here's the project its from. Lines 281
https://codepen.io/sharperwebdev/pen/PQvMqR?editors=0011
The Array#filter method would be more appropriate for this. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
const filteredMarkers = mapMarkers.filter(marker => markerID !== marker.id);
Then use filteredMarkers (mapMarkers isn't mutated, which is a better practice).