MongoDB $elemMatch in Meteor - arrays

I have a small question about $elemMatch. This is a document in MongoDB:
{
_id:'asdf1234',
latest: '2.0.0',
foo : [{
v : '1.0.0',
text : "Hello"
},{
v: '2.0.0',
text : "Hello v2.0.0"
}]
}
I want to return only foo with v same as in latest field. For now I can do something like this:
var a = function(id, version) {
//id = 'asdf1234'
//version = '2.0.0'
return MyCollection.findOne({_id:id}, {fields:{foo:{$elemMatch:{v:version}}});
}
and I will get foo array only with object with v:'2.0.0'. But now i want to get latest object in array, so parameter version will be 'latest' and function will look like this:
var a = function(id, version) {
//id = 'asdf1234'
//version = 'latest'
if(version != 'latest') {
return MyCollection.findOne({_id:id}, {fields:{foo:{$elemMatch:{v:version}}});
} else {
var doc = MyCollection.findOne({_id:id});
//Some code to get object where v == doc.latest
}
}
And now question - can I get element from foo Array only with one query, something like this:
MyCollection.findOne({_id:id}, {fields:{foo:{$elemMatch:{v:'$latest? or fields.latest?'}}});
I don't want to iterate through array to get latest element. Of course, if there is no chance to get it like this, I will write finding code :)
Thanks for any answers!

Mongo find will give you the complete document with all entries in your array. It's not possible to select one of the foo array's items with a Mongo query. You need to find the correct subdocument once you have the array.
Fortunately, it's quite simple:
_.find(doc.foo, function(item) {return item.v === doc.latest});

Related

Swift - How to update object in multi-dimensional directory

I want to be able to find and update a custom object in an array of these objects. The challenge is that the custom objects also can be children of the object.
The custom object looks like this:
class CustomObject: NSObject {
var id: String?
var title: String?
var childObjects: [CustomObject]?
}
I would like to be able to create a function that overwrites the custom object with fx a specific ID, like this:
var allCustomObjects: [CustomObject]?
func updateCustomObject(withId id: String, newCustomObject: CustomObject) {
var updatedAllCustomObjects = allCustomObjects
// ...
// find and update the specific custom object with the id
// ...
allCustomObjects = updatedAllCustomObjects
}
I recognize this must be a pretty normal issue regarding multidimensional arrays / directories in both Swift and other languages. Please let me know what normal practice is used for this issue.
As with most things to do with trees, recursion is going to help. You can add an extra parameter that indicates which array of CustomObjects that you are currently going through, and returns a Bool indicating whether the ID is found, for short-circuiting purposes.
#discardableResult
func updateCustomObject(withId id: String, in objectsOrNil: inout [CustomObject]?, newCustomObject: CustomObject) -> Bool {
guard let objects = objectsOrNil else { return false }
if let index = objects.firstIndex(where: { $0.id == id }) {
// base case: if we can find the ID directly in the array passed in
objectsOrNil?[index] = newCustomObject
return true
} else {
// recursive case: we need to do the same thing for the children of
// each of the objects in the array
for obj in objects {
// if an update is successful, we can end the loop there!
if updateCustomObject(withId: id, in: &obj.childObjects, newCustomObject: newCustomObject) {
return true
}
}
return false
// technically I think you can also replace the loop with a call to "contains":
// return objects.contains(where: {
// updateCustomObject(withId: id, in: &$0.childObjects, newCustomObject: newCustomObject)
// })
// but I don't like doing that because updateCustomObject has side effects
}
}
You would call this like this, with the in: parameter being allCustomObjects.
updateCustomObject(withId: "...", in: &allCustomObjects, newCustomObject: ...)

Modify an array element after finding it in swift does not work

I wrote a model like this as an exercise :
struct Store {
var name : String
var bills : Array<Bill>
var category : Category?
}
struct Bill {
var date : String
var amount : Float
}
struct Category {
var name : String
var tags : Array<String>
}
and when I'm searching if a store already exist to add a bill to it instead of creating a new store, my code doesn't work. It acts like if the result of the search is a copy of the Array element . I would like to have a reference.
var stores : Array <Store> = Array()
for billStatment in billStatements! {
let billParts = billStatment.split(separator: ",")
if billParts.count > 0 {
let bill : Bill = Bill(date:String(billParts[0]), amount: Float(billParts[2])!)
var store : Store = Store(name:String(billParts[1]), bills: [bill], category: nil)
if var alreadyAddedStore = stores.first(where: {$0.name == String(billParts[1])}) {
alreadyAddedStore.bills.append(bill)
print("yeah found it \(alreadyAddedStore)") // the debugger breaks here so I know the "first" method is working. If I print alreadyAddedStore here I have one more element, that's fine.
} else {
stores.append(store)
}
}
}
print("\(stores.count)") // If I break here for a given store that should contains multiple elements, I will see only the first one added in the else statement.
Can anyone tell me what I am doing wrong?
As already noted, you're confusing value (struct) semantics with reference (class) semantics.
One simple fix would be the change stores to a dictionary with the name as your key:
var stores : Dictionary<String, Store> = [:]
and use it like this:
if(stores[store.name] == nil) {
stores[store.name] = store
}
else {
stores[storeName].bills.append(bill)
}

Fuzzy modules Return JSON Array of Matched word?

I'm using fuzzy module with node but I have long JSON Array contain object. I need matched object whole. Like
link of module
Fuzzy Modules
var list = [
{rompalu: 'baconing', zibbity: 'simba'}
, {rompalu: 'narwhal' , zibbity: 'mufasa'}
, {rompalu: 'a mighty bear canoe', zibbity: 'saddam hussein'}
];
I have above list of JSON Array and if I pass word narwhal than It's return only matched words in Array but I need array of matched object. output like :
[
{rompalu: 'narwhal' , zibbity: 'mufasa'}
]
There seem to be various options.
Filter the list manually using fuzzy.test():
var results = list.filter(function(obj) {
return fuzzy.test('narwhal', obj.rompalu);
});
Extract the "originals":
var options = { extract: function(el) { return el.rompalu; } };
var results = fuzzy.filter('narwhal', list, options).map(function(r) {
return r.original;
});

AngularJS and JSON returns undefined

Hi I have got a data in LocalStorage as JSON string:
[
{"Date":"28/04/2016","Time":"08:00","Title":"Title 1"},
{"Date":"28/04/2016","Time":"08:30","Title":"Title 2"}
]
And my module.factory looks like:
module.factory('$schedule', function() {
var schedule = {};
var result = JSON.parse(localStorage.getItem('myAgenda'));
schedule.items = [{
title: result.Title,
date: result.Date,
time: result.Time
}];
return schedule;
});
When I am trying to get data it returns undefined. When I try to get a specific object like:
console.log(result[0].Title);
It works fine and shows only the first element. I guess I missing each definition but don't know how to do it. Please help me to get all results in my schedule.items.
And I am passing the result as items into:
module.controller('ScheduleController', function($scope, $schedule) {
$scope.items = $schedule.items;
});
Many thanks.
You are trying to access fields in an array without mentioning wich array element you want to access. If you want to enumerate all agenda entries and add them to your array, it should look something like this:
module.factory('$schedule', function () {
var schedule = [];
var result = JSON.parse(localStorage.getItem('myAgenda'));
result.forEach(function (date) {
schedule.push({
title: date.Title,
date: date.Date,
time: date.Time
})
})
return schedule;
});
You should use .map over array, also add missing } in your last element of array.
var schedule = [];
//assuming result returns an array.
schedule = result.map(function(value){
return {
title: value.Title,
date: value.Date,
time: value.Time
};
})
Not familiar with module.factory, but it looks like result is an array of objects and you're accessing it like a single object when creating schedule.items.
You might have to iterate over the array and create an item per object in result.

How to filter object from array by value and using the value to omit another array or objects?

I have a array, which has the bunch of object, i would like to filter the object by 'name' value, again i would like to omit those object from another array of object using underscore.
I know that we can do using earch, but i am not getting the proper approach to do this both..
any one help me to do this?
example :
incoming array:
var incomingArray = [
{"name":"apple"},
{"name":"orange"},
{"name":"dog"},
{"name":"cat"},
{"name":"egle"}
];
filter keys:
var omit = ['orange' ,'dog'];
//i need to check whether 'orange' or 'dog' are exist, if so..
var filtered = _.filter(incomingArray, function(obj, i){
return obj.name === omit[i]['name'];//this is wrong i need to loop again how?
});
var anotherArray = [
{"name":"apple"},
{"name":"orange"},
{"name":"dog"},
{"name":"cat"},
{"name":"egle"}
]
return only the array without the omit like this:
var outgoingArray = [
{"name":"apple"},
{"name":"cat"},
{"name":"egle"} ]
how we could achieve this with proper approach?
demo
You were nearly there! Use indexOf to check that the name does not belong in the omit array:
var filtered = _.filter(incomingArray, function(obj) {
return omit.indexOf(obj.name) == -1;
});

Resources