BackboneJS: Sorting collection of linked items - javascript

I have some trouble figuring out how to sort a BackboneJS collection containing linked items.
Is it at all possible to do efficiently? (I am thinking of making one returning the count of previous elements, but that is really inefficient)
What should the comparator be? - and is a double linked list required?
My items look like
[
{
id: 1,
name: 'name',
previousItem: 2
},
{
id: 2,
name: 'othername',
previousItem: null
}
]

Here is the basic code to build the collection. I'm assuming you are using a Backbone Model here. In the loop, you need to add your models to the front of the collection (unshift) since you only know the previous item.
The key here is knowing what the last item is though. If you don't know it, then this will not work.
model = frontItem;
while (model != null) {
collection.unshift(model);
model = model.attr('previousItem')
}

there is a discussion about this on github, you can also use comparator, if you want to use comparator you need underscore
var PhotoCollection = Backbone.Collection.extend({
model: Photo,
comparator: function(item) {
return item.get('pid');
}
});

Related

Reading/writing nested data in a Firebase Database (web)

This seemingly simple question is surely a duplicate of many, so I apologize for that. Won't be offended when it's marked as such... But I have yet to find a clear, straight forward and modern answer that seems to work as I'd expect.
Given "Item One", how can I return the "subItems" array for the object that matches that title?
Additionally, how do I push new subitems to that array (if there's some different way I should target that array when writing rather than reading)
And the context of this is "items" is the top-level db.ref('items')
To find an item by a property, you need to run a query that orders and filters on that property. So in your case:
var ref = firebase.database().ref("items");
var query = ref.orderByChild("title").equalTo("Item One");
query.once("value", function(snapshot) {
snapshot.forEach(function(item) {
console.log(item.key); // -L8...EMj7P
console.log(item.child("subItems").val()); // logs the sub items
// console.log(item.ref.child("subItems").push().set(...)); // adds a sub item
});
});
Note that nesting data types is an anti-pattern in the Firebase Database, since it typically leads to problems later on. A more idiomatic approach is to have two top-level lists (e.g. items and subItems) that then use the same keys:
items: {
-L8...EMj7P: {
title: "Item One"
}
},
subItems: {
-L8...EMj7P: {
...
}
}

Create/update objects with mongoose/mongoDB

The internet is full of resources for dealing with arrays, but often objects are a more natural fit for data and seemingly more efficient.
I want to store key-value objects under dynamic field names like this:
project['en-US'] = { 'nav-back': 'Go back', ... }
project['pt-BR'] = { 'nav-back': 'Volte', ... }
Doing this seems like it would be more efficient than keeping an array of all languages and having to filter it to get all language entries for a given language.
My question is: How can I insert a key-value pair into an object with a dynamic name using mongoose? And would the object need to exist or can I create it if it doesn't in one operation?
I tried this:
await Project.update(
{ _id: projectId },
{
$set: {
[`${language}.${key}`]: value,
},
});
But no luck regardless of if I have an empty object there to begin with or not: { ok: 0, n: 0, nModified: 0 }.
Bonus: Should I index these objects and how? (I will want to update single items)
Thanks!
In mongoose, the schema is everything. It describe the data you gonna read/store from the database. If you wanna add dynamically a new key in the schema it's gonna be hard.
In this particulary case I would recommend to use the mongodb-native-driver which is way more permissive about the data manipulation. So you could read the data in a specific format and dynamically add your field into it.
To resume my thought, how should your dynamic change happen :
Use mongodb-native-driver to insert the new key into the database data
Modify the mongoose schema you have in the code (push a new key into it)
Use mongoose to manipulate the data afterward
Do not forget to dynamically update your mongoose model or you won't read the new key at the next find.
I solved this using the original code snippet unchanged, but adding { strict: false } to the schema:
const projectSchema = new Schema({ ...schema... }, { strict: false });

Fastest way to add to and get values from a list of objects

I'm just getting started with JavaScript objects. I'm trying to store catalog inventory by id and locations. I think a single object would look something like this:
var item = {
id: number,
locations: ["location1", "location2"]
};
I've started to read a bit about it but am still trying to wrap my head around it. Not sure what is the fastest way add new items to a list with a location, add a new location to an existing item, all while checking for dupes. Performance of getting the locations later isn't as critical. This is part of a process that is running thousands of checks to eventually get items by id and location, so performance is key.
Final question, I'm not even sure if it's possible to store this in local storage. From another similar question, I'm not sure.
Using lodash, something like this should work to determine if an item id exists and append either a new item to the array, or just add a new location:
var item = [{
id: 1,
locations: ["location1", "location2"]
},{
id: 2,
locations: ["location2", "location4"]
}];
function findItem(id){
return _.findIndex(item, function(chr) {
return chr.id == id;
});
}
function addItem(id,locations) {
var position = findItem(id);
if (position<0) {
item.push({
id: id,
locations: locations
})
} else {
item[position].locations = _.uniq(item[position].locations.concat(locations));
}
}
addItem(2,['location292']);
addItem(3,['location23']);
console.log(item);
What it basically does is to search the array of objects (item) for an id as the one we are passing to the addItem() function, if it is found we add the new locations array to the existing item, if not it's creating a new object with a new id and location.
You've asked a question that contains some tradeoffs:
The simplest and fastest way to retrieve a list of locations is to store them in an array.
The fastest way to check something for a duplicates is not an array, but rather a map object that maintains an index of the key.
So, you'd have to discuss more about which set of tradeoffs you want. Do you want to optimize for performance of adding a non-duplicate or optimize for performance of retrieving the list of locations. Pick one or the other.
As for localStorage, you can store any string in LocalStorage and you can convert simply non-reference objects to a string with JSON.stringify(), so yes this type of structure can be stored in LocalStorage.
For example, if you want to use the array for optimized retrieval, then you can check for duplicates like this before adding:
function addLocation(item, newLocation) {
if (item.locations.indexOf(newLocation) === -1) {
item.locations.push(newLocation);
}
}
Also, you can store an array of items in LocalStorage like this:
localStorage.setItem("someKey", JSON.stringify(arrayOfItems));
And, then some time later, you can retrieve it like this:
var arrayOfItems = JSON.parse(localStorage.getItem("someKey"));

MongoDB - Query conundrum - Document refs or subdocument

I've run into a bit of an issue with some data that I'm storing in my MongoDB (Note: I'm using mongoose as an ODM). I have two schemas:
mongoose.model('Buyer',{
credit: Number,
})
and
mongoose.model('Item',{
bid: Number,
location: { type: [Number], index: '2d' }
})
Buyer/Item will have a parent/child association, with a one-to-many relationship. I know that I can set up Items to be embedded subdocs to the Buyer document or I can create two separate documents with object id references to each other.
The problem I am facing is that I need to query Items where it's bid is lower than Buyer's credit but also where location is near a certain geo coordinate.
To satisfy the first criteria, it seems I should embed Items as a subdoc so that I can compare the two numbers. But, in order to compare locations with a geoNear query, it seems it would be better to separate the documents, otherwise, I can't perform geoNear on each subdocument.
Is there any way that I can perform both tasks on this data? If so, how should I structure my data? If not, is there a way that I can perform one query and then a second query on the result from the first query?
Thanks for your help!
There is another option (besides embedding and normalizing) for storing hierarchies in mongodb, that is storing them as tree structures. In this case you would store Buyers and Items in separate documents but in the same collection. Each Item document would need a field pointing to its Buyer (parent) document, and each Buyer document's parent field would be set to null. The docs I linked to explain several implementations you could choose from.
If your items are stored in two separate collections than the best option will be write your own function and call it using mongoose.connection.db.eval('some code...');. In such case you can execute your advanced logic on the server side.
You can write something like this:
var allNearItems = db.Items.find(
{ location: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ <longitude> , <latitude> ]
},
$maxDistance: 100
}
}
});
var res = [];
allNearItems.forEach(function(item){
var buyer = db.Buyers.find({ id: item.buyerId })[0];
if (!buyer) continue;
if (item.bid < buyer.credit) {
res.push(item.id);
}
});
return res;
After evaluation (place it in mongoose.connection.db.eval("...") call) you will get the array of item id`s.
Use it with cautions. If your allNearItems array will be too large or you will query it very often you can face the performance problems. MongoDB team actually has deprecated direct js code execution but it is still available on current stable release.

Reordering objects in an array of objects

I have a json object that looks something like:
{
posts: [
{id: 56, title: 'something', date: '10-10-10 00:00:00'},
{id: 57, title: 'Apples', date: '10-10-16 00:00:00'},
]
}
And I am trying to learn how to manipulate data structures in Javascript. I would like to use jquery to reorder these based on the posts attributes, so you might reorder based on date, title or id (default is id).
How ever being a novice, I have no idea where to start I have seen this answer andI dont think its the direction I want to go.
Would the resulting out put be in the same structure? How could I create a collections of models based off this kind of "re-ordering".
The idea is to allow for editing and publishing of one model in a collection, based off the attribute used to re-order or "sort" the collection, thus allowing for faster processing - so I don't always have to pass the whole collection to the server when I really just want to update one model in the collection.
Take a look at the JavaScript array.sort method. It may do what you want.
var posts = [{"id": 57, "title": "something"}, {"id": 56, "title": "something else"}];
posts.sort(function(a, b) { if (a.id < b.id) { return -1; } else { return 1; } });
for (var i=0; i<posts.length-1; i++) {
console.log(posts[i].title);
}
// prints "something else" followed by "something"
The sort method takes a function which is passed two elements, a and b, and you can return -1 if a is less than b, 0 if they are equal, and 1 if a is greater than b.
Note that my posts variable above is just a simplified version of what would be o.posts if your described JSON was stored at o. Also note that sort sorts in place, meaning it will change the array it operates over.

Categories