Doc with ObjectId Array - push value if exists, remove otherwise - arrays

I'm new to MongoDB and mongoose.
So my model holds many fields, amongst them is an Array of ObjectIDs
var modelSchema = new Schema({
//...
inner_array: [Schema.Types.ObjectId],
//...
});
What I'm trying to achieve with my query is:
Find a model by it's Id,
If the inner array contains a specific value remove it from the array.
If the value is not within the inner_array, push it
var target_id = // document id
var inner_object_id = // value to push
models.MyModel.findOne(
{_id: target_id},
function (err, model) {
// IN THIS SCOPE 'INNER_OBJECT_ID' IS UNDEFINED
// if model.inner_array contains 'inner_object_id', remove it
// otherwise, push 'inner_object_id' into model.inner_array
model.save();
res.json(model); // return modified document to client
}
);
I believe this can be written in a single findOneAndUpdate, but I can't figure out the syntax..
Thanks alot!

I believe you can achieve that using MongooseArray.pull and MongooseArray.addToSet
var target_id = // document id
var inner_object_id = // value to push
models.MyModel.findOne({
_id: target_id
}, function (err, model) {
if (model.inner_array.indexOf(inner_object_id) !== -1) {
model.inner_array.pull(inner_object_id);
} else {
model.inner_array.addToSet(inner_object_id);
}
model.save();
res.json(model); // return modified document to client
}

Related

Extending $firebaseArray with an extended $firebaseObject

Trying to cut down code repetition, I've set up a $firebaseArray extension as follows:
var listUsersFactory = $firebaseArray.$extend({
$$added: function (snap) {
return new Customer(snap);
},
$$updated: function (snap) {
var c = this.$getRecord(snap.key);
var updated = c.updated(snap);
return updated;
},
});
and the Customer code:
function Customer(snap) {
this.$id = snap.key;
this.updated(snap);
}
Customer.prototype = {
updated: function(snap) {
var oldData = angular.extend({}, this.data);
this.data = snap.val();
// checks and such
}
}
This works wonders when loading, showing and saving a list of customers, and I'm satisfied with it.
Now, the problem lies in retrieving a single customer and its detail page, because the Customer object isn't an extension of $fireObject and is therefore lacking a $save method
Single customer loading:
customersRef.once("value", function(snapshot) {
if(snapshot.child(uuid).exists())
{
customersFactory.customerDetails = new Customer(snapshot.child(uuid));
return deferred.resolve();
}
}
but when I call customersFactory.customerDetails.$save() I get an error
How can I extend my class so that it works for both array and single object uses?
I couldn't find a way to do this, so I ended up using the $firebaseArray and getting single records off that to pass as details, in case anyone's wondering

Return value from angularjs factory

I try to set up this example https://github.com/AngularClass/angular-websocket#usage
Here is my code
App.factory('MyData', function($websocket, $q) {
var dataStream = $websocket('wss://url');
var collection = [];
dataStream.onMessage(function(message) {
var result = JSON.parse(message.data);
console.log(result);
collection = result;
});
var methods = {
collection: collection,
get: function() {
dataStream.send(JSON.stringify({
api: "volume",
date: "2017-02-01",
interval: 600
}));
}
};
return methods; });
In my controller I wrote:
$interval(function () {
console.log(MyData.collection);
}, 1000);
The problem is that I don't receive any values, however on message arrive I see console log, so websocket itself is obviously alive. If I change collection.push(result) (like in example) I receive constantly growing array. I need only the last value, however. Why collection = result is wrong ?
var collection = []; instantiates a new array and its reference is stored in the variable collection. Then, this reference is assigned to methods.collection and, hence, MyData.collection. However, with JSON.parse a new array is instantiated. collection = result; overwrites the original reference with the reference of the new array. But MyData.collection still holds the reference to original array.
So, there are two ways to encounter the problem:
Don't overwrite the reference to the original array. push is good, but before, you need to clear the array in order to only show the last value.
collection.splice(0, collection.length);
collection.push(result);
However, that would be an array in an array. You probably need to push the values individually (Array.concat will create a new array, too):
collection.splice(0, collection.length);
result.forEach(function(value) {
collection.push(value);
});
Assign the reference of the new array directly to methods.collection. In this case, no extra variable collection is needed.
App.factory('MyData', function($websocket, $q) {
var dataStream = $websocket('wss://url');
var methods = {
collection: [],
get: function() {
dataStream.send(JSON.stringify({
api: "volume",
date: "2017-02-01",
interval: 600
}));
}
};
dataStream.onMessage(function(message) {
var result = JSON.parse(message.data);
console.log(result);
methods.collection = result;
});
return methods;
});

Creating nested array in firebase Object

I want to push a value to a nested array which is stored in my firebase database. The target looks like this:
I'm query the firebase database and receive snapshot. With this snapshot I want to store my changes. If i push the new value it creates me in firebase this:
How can I avoid the unique FB id and replace it with a normal index counter?
My code from the angular service:
//Save StarBewertung on Mamis
this.saveStarOnMami = function (data) {
var ref = new Firebase("https://incandescent-heat-5149.firebaseio.com/contacts")
var query = ref.orderByChild("id").equalTo(data).on("child_added", function(snapshot) {
if( snapshot.val() === null ) {
/* does not exist */
} else {
//snapshot.ref().update({"phone_fixed": '123'});
snapshot.ref().child('rateData').push(1);
}
});
}
Is there a way to get the snapshot as an $firebaseobject, manipulate it, and then save it to the Firebase DB with $save?
Thanks...
dbRef.push() will always append the data with a new UID as key.
Use dbRef.update() or dbRef.set() instead.
Example (untested)
var rateSnapshot = snapshot.child('rateData');
if( rateSnapshot.val() === null ) { // rateData key does not exist
rateSnapshot.ref().set([5]);
} else {
var rates = rateSnapshot.val(); //should be an array
rates.push(1); //append new value to the array
rateSnapshot.ref().set(rates);
}

Extjs 4.2 store.getRange gives data of previously loaded store

I have an extjs store associated with grid class. when I select a class, it gives ClassID of the record.
var ClassData = record.get('ClassID');
console.log(ClassData);
Based on this ClassID I am loading store of next grid:
var Grid = this.getSemGrid();
var Store = Grid.getStore(); // your grid's store
//load store with records having selected class ID
var g = Store.load( {params : {ClassID: ClassData }});
Till here everything is fine.
Once the store is loaded, I am getting all loaded records (Error Area)
var selected = g.getRange(); // getRange = select all records
Then pushing all the values of one field of all records in an array
var Excerpt = []; // start with empty array
Ext.each(selected, function(item) {
// add the fields that you want to include
var Obj = {
third_field: item.get('ExamName')
};
Excerpt.push(Obj); // push this to the array
}, this);
console.log(Excerpt);
Excerpt gives array of previously selected record not the current record.
I have also tried
Store.loadData([],false);
to clear all the loaded data of store before loading it again.
Got this working
var g = Store.load({
params : {ClassID: ClassData },
callback : function(records, operation, success){
var Excerpt = []; // start with empty array
Ext.each(records, function(item) {
// add the fields that you want to include
var Obj = {
third_field: item.get('ExamName')
};
Excerpt.push(Obj); // push this to the array
}, this);
}
});

passing data to a collection in backbone

So I am trying storing product types from a json file before trying to add them to a collection but am getting some strange results (as in I dont fully understand)
on my router page i setup a variable for cached products as well as product types
cachedProductTypes: null,
productType : {},
products : {},
getProductTypes:
function(callback)
{
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
var self = this;
$.getJSON('data/product.json',
function(data)
{
self.cachedProductTypes = data;
callback(data);
}
);
},
parseResponse : function(data) {
result = { prodTypes: [], products: [] };
var type;
var types = data.data.productTypeList;
var product;
var i = types.length;
while (type = types[--i]) {
result.prodTypes.push({
id: type.id,
name: type.name,
longName: type.longName
// etc.
});
while (product = type.productList.pop()) {
product.productTypeId = type.id,
result.products.push(product);
}
};
this.productType = result.prodTypes;
console.log( "dan");
this.products = result.products;
},
showProductTypes:function(){
var self = this;
this.getProductTypes(
function(data)
{
self.parseResponse(data);
var productTypesArray = self.productType;
var productList=new ProductsType(productTypesArray);
var productListView=new ProductListView({collection:productList});
productListView.bind('renderCompleted:ProductsType',self.changePage,self);
productListView.update();
}
);
}
when a user goes to the show product types page it runs the showProductsType function
So I am passing the products type array to my collection
on the collection page
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
$.each(this.productTypesArray, function(i,prodType){
tmpItem=new ProductType({id:prodType.id, name:prodType.name, longName:prodType.longName});
console.log(prodType.name);
self.add(tmpItem);
});
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
now this doesnt work as it this.productTypesArray is undefined if i console.log it.
(how am I supposed to get this?)
I would have thought I need to go through and add each new ProductType.
the strange bit - if I just have the code
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
it actually adds the products to the collection? I guess this means I can just pass an array to the collection and do not have to add each productType?
I guess this means I can just pass an array to the collection and do not have to add each productType?
Yes, you can pass an array to the collection's constructor, and it will create the models for you.
As far as your caching code, it looks like the problem is here:
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
The callback statement's argument is missing this - should be return callback(this.cachedProductTypes).

Resources