I want to atomically remove the first n elements of an array field.
Right now, I use model.find(), then doc.arrayField.slice(n), then doc.save(). But this loads the entire document in memory (bad if document is very large), and it would kill the atomicity.
Is there a way to achieve this atomically in MongoDB/Mongoose?
Thanks!
You can use $pop to remove first element atomically. Or if you can specify which fields to remove you can use $pull to remove multiple items from an array. Otherwise you cannot remove first n elements from array in an atomic operation using mongodb.
db.yourCollection.update({}, {$pop: {arrayField: 1}}}) // will remove the first element from arrayField
db.yourCollection.update({}, {$pull: {arrayField: {foo: "bar"}}}}) // will remove all elements whose foo field equal to bar from arrayField.
MongoDB provides $slice operator for array updates. https://docs.mongodb.org/v3.0/reference/operator/update/slice/
You can use in Mongoose updateClause too.
Instead of loading all arrayField data in memory, you can use $slice to project docs with first n elements of arrayFields like this
model.find({}, {arrayField : {$slice: n}}) // n is first n elements
Now you can remove those n elements using
doc.arrayField.slice(n);
doc.save();
Related
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);
This is the JSON stored in my chrome local storage
{"users":[
{"password":"123","userName":"alex"},
{"password":"234","userName":"dena"},
{"password":"343","userName":"jovit"}
]}
Is it possible to remove a specific item in "users" ?
I tried to this code but no luck
chrome.storage.local.remove('users[0]', function(){
alert('Item deleted!');
});
There is no magic syntax to delete only one element from an array that is stored in chrome.storage. In order to delete an item from the array, you has to retrieve the stored array, throw away the unwanted items (or equivalently, keep only the items that you want to keep), then save the array again:
chrome.storage.local.get({users: []}, function(items) {
// Remove one item at index 0
items.users.splice(0, 1);
chrome.storage.set(items, function() {
alert('Item deleted!');
});
});
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice.
Note that if you want to delete one or more items whose value satisfies a certain condition, you have to walk the array in reverse order. Otherwise you may end up removing the wrong items since the indices of the later elements are off by one after removing the first item, off by two when you've removed two items, etc.
Yes you can try this
chrome.storage.sync.remove("token");
see documentation
I want to add an array dynamically using jquery. How can i do that.(or)
I want to push the elements in to array like this.
var array = [{"question":"1","answer":"2"}];
i want to do that dynamically using for loop i mean
initially i will add
array.push({"question":"1"});
then array.push({"answer":"2"});
but I want the elements to in the same array[0] element
but it is taking as array[0],array[1]
How can I do that. I am using for loop to add the elements in to an array.
If you are pushing an answer immediately after, can you not do something like
array[index] = { "question" : array[index].question, "answer": 2 };
If not you will have to find some other way of finding the index where the question was pushed and then
Just note that array.push always adds a new object to the array, and does not update it.
I need help with a loop... it's probably simple but I'm having difficulty coding it up.
Basically, I need to check existing Ids for their number so I can create a unique id with a different number. They're named like this: id="poly'+i'" in sequence with my function where i is equal to the number of existing elements. Example: Array 1, Array 2, Array 3 corresponding with i=1 for the creation of Array 1, i=2 for Array 2, etc.
Right now i is based on the total number of existing elements, and my "CreateNew" function is driven off x=i+1 (so the example above, the new element will be named Array 4). The problem is that if you delete one of the middle numbers, the "Create" function will duplicate the high number. i.e. Array 1, 2, 3 delete 2, create new-> Array 1, 3, 3.
I need an if() statement to check if the array already exists then a for() loop to cycle through all i's until it validates. Not sure how to code this up.
The code I'm trying to correct is below (note I did not write this originally, I'm simply trying to correct it with my minimal JS skills):
function NewPanel() {
var i = numberOfPanels.toString();
var x = (parseInt(i)+1).toString();
$('#items').append('<div onclick="polygonNameSelected(event)" class="polygonName" id="poly'+i+'"> Array '+ x +' </div>');
$('div[id*=poly]').removeClass('selected');
$('#poly'+i).addClass('selected');
$('#poly'+i).click(function() {
selectedPolygon = i;
$('div[id*=poly]').removeClass('selected');
$(this).addClass('selected');
});
}
THANK YOU! :)
Please clarify "The problem is that if you delete one of the middle numbers, ". What do you mean by delete? Anyway, the simplest solution is to create two arrays. Both arrays will have the same created id's. Whenever an id is created in the first array, an id will be added to the second array. So when it is deleted from first array, check your second array's highest value and then create this id in first array. I hope this did not confuse you.
Well it is hard to tell why you cannot just splice the array down. It seems to me there is a lot of extra logic involved in the tracking of element numbers. In other words, aside from the index being the same, the ids become the same as well as other attributes due to the overlapping 1, 3, 3 (from the example). If this is not the case then my assumption is incorrect.
Based on that assumption, when I encounter a situation where I want to ensure that the index created will always be an appending one, I usually take the same approach as I would with a database primary key. I set up a field:
var primaryKeyAutoInc = 0;
And every time I "create" or add an element to the data store (in this case an array) I copy the current value of the key as it's index and then increment the primaryKeyAutoInc value. This allows for the guaranteed unique indexing which I am assuming you are going for. Moreover, not only will deletes not affect future data creation, the saved key index can be used as an accessor.
This is my code:
function insert(){
var loc_array = document.location.href.split('/');
var linkElement = document.getElementById("waBackButton");
var linkElementLink = document.getElementById("waBackButtonlnk");
linkElement.innerHTML=loc_array[loc_array.length-2];
linkElementLink.href = loc_array[loc_array.length];
}
I want linkElementLink.href to grab everything but the last item in the array. Right now it is broken, and the item before it gets the second-to-last item.
I’m not quite sure what you’re trying to do. But you can use slice to slice the array:
loc_array = loc_array.slice(0, -1);
Use pathname in preference to href to retrieve only the path part of the link. Otherwise you'll get unexpected results if there is a ?query or #fragment suffix, or the path is / (no parent).
linkElementLink.href= location.pathname.split('/').slice(0, -1).join('/');
(But then, surely you could just say:)
linkElementLink.href= '.';
Don't do this:
linkElement.innerHTML=loc_array[loc_array.length-2];
Setting HTML from an arbitrary string is dangerous. If the URL you took this text from contains characters that are special in HTML, like < and &, users could inject markup. If you could get <script> in the URL (which you shouldn't be able to as it's invalid, but some browser might let you anyway) you'd have cross-site-scripting security holes.
To set the text of an element, instead of HTML, either use document.createTextNode('string') and append it to the element, or branch code to use innerText (IE) or textContent (other modern browsers).
If using lodash one could employ _.initial(array):
_.initial(array): Gets all but the last element of array.
Example:
_.initial([1, 2, 3]);
// → [1, 2]
Depending on whether or not you are ever going to reuse the array you could simply use the pop() method one time to remove the last element.
linkElementLink.href = loc_array[loc_array.length]; adds a new empty slot in the array because arrays run from 0 to array.length-1; So you returning an empty slot.
linkElement.innerHTML=loc_array[loc_array.length-2]; if you use the brackets you are only getting the contents of one index. I'm not sure if that is what you want? The next section tells how to get more than one index.
To get what you want you need for the .href you need to slice the array.
linkElementLink.href = loc_array.slice(0,loc_array.length-1);
or using a negative to count from the end
linkElementLink.href = loc_array.slice(0,-1);
and this is the faster way.
Also note that when getting to stuff straight from the array you will get the same as the .toString() method, which is item1, item2, item3. If you don't want the commas you need to use .join(). Like array.join('-') would return item1-item2-item3. Here is a list of all the array methods http://www.w3schools.com/jsref/jsref_obj_array.asp. It is a good resource for doing this.
.slice(number you want)
if you just want the first 4 elements in an array its array.slice(3)
doing a negative number starts from the end of the array