instead of an array:
var arrayExample = {
"lotsOfStuff" : [
{"id" : "th1", "name" : "thing1", "type": "thing", "moo":"a"},
{"id" : "th2", "name" : "thing2", "type": "thing", "moo":"z"},
{"id" : "th3", "name" : "aDifferentThing3", "type": "differentThing", "moo":"m"}
]
}
Use lots of properties:
var propertyExample = {
"lotsOfStuff" : {
"id1" : {"name" : "thing1", "type" : "thing", "moo" : "a" },
"id2" : {"name" : "thing2", "type" : "thing", "moo" : "z" },
"id3" : {"name" : "aDifferentThing3", "type" : "differentThing", "moo" : "m" }
}
}
can still iterate through them
for(var idx in arrayExample.lotsOfStuff) {
var thing = lotsOfStuff[idx];
var id = thing.id;
...
}
and
for(var id in propertyExample) {
var thing = lotsOfStuff[id];
...
}
but you have the bonus of a lookup by id at the expense of the lookup by index position
Any problems with using this array alternative??
what about performance with lots of elements??
If the order of the elements matters, use an array.
If you need to look up by ID, use an object.
If you need to do both, create both an array and an object whose elements point to the same objects.
Accessing object properties is probably slower than accessing array elements, because it requires hashing instead of simple indexing. But if you need to look up by ID in an array, that will require a linear search, which is much slower than hashing if there are lots of elements. The performance of objects should not be impacted significantly by the number of elements.
Related
I'm using a model tree structures with an array of ancestors and I need to check if any document is missing.
{
"_id" : "GbxvxMdQ9rv8p6b8M",
"type" : "article",
"ancestors" : [ ]
}
{
"_id" : "mtmTBW8nA4YoCevf4",
"parent" : "GbxvxMdQ9rv8p6b8M",
"ancestors" : [
"GbxvxMdQ9rv8p6b8M"
]
}
{
"_id" : "J5Dg4fB5Kmdbi8mwj",
"parent" : "mtmTBW8nA4YoCevf4",
"ancestors" : [
"GbxvxMdQ9rv8p6b8M",
"mtmTBW8nA4YoCevf4"
]
}
{
"_id" : "tYmH8fQeTLpe4wxi7",
"refType" : "reference",
"parent" : "J5Dg4fB5Kmdbi8mwj",
"ancestors" : [
"GbxvxMdQ9rv8p6b8M",
"mtmTBW8nA4YoCevf4",
"J5Dg4fB5Kmdbi8mwj"
]
}
My attempt would be to check each ancestors id if it is existing. If this fails, this document is missing and the data structure is corrupted.
let ancestors;
Collection.find().forEach(r => {
if (r.ancestors) {
r.ancestors.forEach(a => {
if (!Collection.findOne(a))
missing.push(r._id);
});
}
});
But doing it like this will need MANY db calls. Is it possible to optimize this?
Maybe I could get an array with all unique ancestor ids first and check if these documents are existing within one db call??
First take out all distinct ancesstors from your collections.
var allAncesstorIds = db.<collectionName>.distinct("ancestors");
Then check if any of the ancesstor IDs are not in the collection.
var cursor = db.<collectionName>.find({_id : {$nin : allAncesstorIds}}, {_id : 1})
Iterate the cursor and insert all missing docs in a collection.
cursor.forEach(function (missingDocId) {
db.missing.insert(missingDocId);
});
I have a problem with multiplying an array of key-value pairs in Meteor / MongoDB. I want to multiply an entire ingredient list with a fixed value. The collection looks like this:
"ingredients" : [
{
"ingredient" : "noodle",
"amount" : 500,
"unit" : "g"
},
{
"ingredient" : "cheese",
"amount" : 100,
"unit" : "g"
}
],
Now, I want to multiply the amount value with a certain number multip, let's say 1,5. The desired output would look like:
"ingredients" : [
{
"ingredient" : "noodle",
"amount" : 750,
"unit" : "g"
},
{
"ingredient" : "cheese",
"amount" : 150,
"unit" : "g"
}
],
Right now I have this:
for (i in this.ingredients){
var precalc = this.ingredients[i].amount * multip; //Here's the Multiplicator
var prez=this.ingredients[i].ingredient;
var prem=this.ingredients[i].unit;
Recipes.update(
{"_id": this._id},
{"$set": {
"ingredients":[{ingredient:prez, amount:precalc, unit:prem}]
}}
);
}
I precalculated the new value and used $set because apparently the $mul operator isn't working with meteor. This solution partly works, but unfortunately it overwrites all ingredients and only multiplies the last one (which is obvious). There must be a much simpler way to do that - I just didn't find it. I'm new to MongoDB and Meteor so any help is greatly appreciated!
Don't execute an update for each ingredient, only one for the entire document. I'd do something like this:
let newIngredients = this.ingredients.map(x => {
ingredient: x.ingredient,
amount: x.amount * 1.5,
unit: x.unit
});
Recipes.update(
{_id: this._id},
{$set: {ingredients: newIngredients}}
);
I wanted to do a query to match documents in one collection with documents in another collection based upon a value which should be contained in both sets of documents but, as I have been informed that Mongo does not support a JOIN, I believe I can't do what I want in the way I want to.
My alternative method then is to insert a document into the collection (col1) where I want to do a query and update which contains an array of all the unique cycle number which are in the other collection (col2).
Collection 1 (Col 1)
{
"_id" : ObjectId("5670961f910e1f54662c11ag"),
"objectType" : "Account Balance",
"Customer" : "Thomas Brown",
"status" : "unprocessed",
"cycle" : "1234"
},
{
"_id" : ObjectId("5670961f910e1f54662c12fd"),
"objectType" : "Account Balance",
"Customer" : "Luke Underwood",
"status" : "unprocessed",
"cycle" : "1235"
}
Collection 2 (Col 2)
{
"_id" : ObjectId("5670961f910e1f54662c1d9d"),
"objectOrigin" : "Xero",
"Value" : "500.00",
"key" : "grossprofit",
"cycle" : "1234",
"company" : "e56e09ef-5c7c-423e-b699-21469bd2ea00"
},
{
"_id" : ObjectId("5670961f910e1f54662c1d9f"),
"objectOrigin" : "Xero",
"Value" : "500.00",
"key" : "grossprofit",
"cycle" : "1234",
"company" : "0a514db8-1428-4da6-9225-0286dc2662c1"
},
{
"_id" : ObjectId("5670961f910e1f54662c1da0"),
"objectOrigin" : "Xero",
"Value" : "-127.28",
"key" : "grossprofit",
"cycle" : "1234",
"company" : "c2d0561c-dc5d-44b9-beaf-d69a3472a2b8"
},
{
"_id" : ObjectId("5670961f910e1f54662c1da1"),
"objectOrigin" : "Xero",
"Value" : "-127.28",
"key" : "grossprofit",
"cycle" : "1235",
"company" : "c3fbe6e4-962a-45f6-9ce3-71e2a588438c"
}
So I want to create a document in collection 1 which looks like this:
{
"_id" : ObjectId("5670961f910e1f54662c1d9f"),
"objectType" : "Status Updater",
"cycles" : ["1234","1235"]
}
Now what I want to do is query ALL documents where cycle = cycles and update "status" to "processed". I believe I would do this with a findAndModify with multi : true but not entirely sure.
When finished, I will just simply delete any document in the Collection 1 where objectType is "Status Updater".
If I understand correctly, you want to
a) update all documents in collection #1 where the value of cycle
exists in collection #2.
b) Furthermore, your document of type "objectType" : "Status
Updater" is only a temporary document to keep track of all the cycle
values.
I think you can skip b) and just use the following (this code needs to be executed in the mongo shell):
# get values of all unique cycle values
# returns an array containing: ["1234", "1235", ...]
values = db.coll2.distinct("cycles", {})
# find all documents where cycles value is in the values array
# and update their status.
db.coll1.update({cycles: {$in: values}}, {$set: {status: "processed"}}, {multi: true})
I'm very new to mongoDB and having some problems on joining two collections.
I've read some posts on mapReduce to perform NOSQL way of joining but still having some difficulties here
Collection 1: attraction
{
"_id" : "0001333b-e485-4fee-a0e2-9b7dc338d5a2",
"types" : "Shops",
"name" : "name",
"geo_location" : {
"lat" : 36.0567700000000002,
"lon" : -112.1354520000000008
},
"overall_rating" : 10.0000000000000000,
"num_of_review" : 6,
"review" : [
{
"review_ids" : [
"66ea1cd8-da34-40dc-8ad6-f30df5de9c2c",
"76f51c8d-d2a8-4609-8b7c-c2b0c386e35c",
"185c962a-fcfe-4d03-a3ac-86398be6312a",
"2212535b-28c6-423e-91f7-cc1dfb407d79",
"7e0f1d85-e79e-4bec-9e9c-7dfb03223816",
"f19a83a6-c6ef-4cbe-b90d-f6187bd50baa"
]
}
]
}
Collection 2: attraction_review
{
"_id" : "7e0f1d85-e79e-4bec-9e9c-7dfb03223816",
"user_id" : "somename",
"review_id" : "r122796525",
"unified_id" : "0001333b-e485-4fee-a0e2-9b7dc338d5a2",
"source_id" : "d1057961",
"review_url" : "someURL",
"title" : "some title",
"overall_rating" : 10,
"review_date" : "dates",
"content" : "some contents here",
"source" : "source",
"traval_date" : "dates",
"sort" : ""
}
Basically I need to keep (or copy) the reviews in the attraction_review whose _id has appeared in the review_ids array of the attraction collection.
The example above shows the matching review in red.
It is guaranteed that the attraction_review collection contains every ids in the review_ids for all records in the attraction collection.
The difficulty here is that the review_ids array is within review array, and I am not sure how I would go about mapping many instances of ids.
I would be grateful for some suggestions.
Many thanks
I am trying to extract data from an array in a collection, the extract of code is shown below:
> db.nodes.findOne()
{
"_id" : NumberLong(24060429),
"_t" : "OsmNode",
"uname" : "studerap",
"uid" : 7260,
"version" : 2,
"changeset" : 634057,
"timestamp" : ISODate("2007-11-27T11:18:58Z"),
"tags" : [
[
"created_by",
"almien_coastlines"
],
[
"source",
"PGS"
]
],
"tagKeys" : [
"created_by",
"source"
],
"location" : [
5.5442938804626465,
-6.488432884216309
]
}
The data i actually want to retrieve is 5.5442938804626465 from the location array. Shall it be retrieved through index?
Thanks for helping
To extract that indexed element of array from all documents, you can get through:
var index = 0, count = 1;
var cursor = db.nodes.find({}, {_id:1, location:{$slice:[index, count]}});
Of course, you can write directly:
var cursor = db.nodes.find({}, {_id:1, location:{$slice:[0, 1]}});
Or
var cursor = db.nodes.find({}, {_id:1, location:{$slice:1}});
Then, extract the result:
var results = [];
cursor.forEach(function(e) {
results.push(e.location[0]);
});
By the way, .find() returns a cursor; and .findOne() returns a document, which is equivalent to running .find().next() once if cursor has documents.