I have a weird issue I can't resolve. I have a Mongoose schema:
Product = new Schema({
title: {
type: String
},
prices: {
type: Array
},
sync: {
type: Boolean
}
...
I use the post save middleware to update a 3rd party site if the sync flag is true. On return of that operation I update the prices array and set sync to false so that it will not result in an endless loop.
Product.post('save', function () {
if(this.sync) {
this.title = "HELLO";
this.prices[0].retail = '24';
this.sync = false;
this.save();
}
});
If I do the above the title and sync fields change but not the prices array. Actually I cannot update any array in my schema. In the above example, the prices array contains about 10 entries - each an object that contains many field including a retail field. I have also tried adding to that array:
this.prices.push({ retail: "10 });
As well as reinit the array:
this.prices = [];
No matter what I do it has no effect. Any non array field can however, be updated.
Any ideas what is going on?
If you don't specify what the schema is within an array field (as in prices), Mongoose treats it as a Mixed field and you have to notify Mongoose of any changes you make to it so that Mongoose knows to save it. Docs here.
So your code should change to:
Product.post('save', function () {
if(this.sync) {
this.title = "HELLO";
this.prices[0].retail = '24';
this.markModified('prices');
this.sync = false;
this.save();
}
});
Related
Currently I have a form with 10 fields that I need to do sendkeys > store the value and after assert this value when save the form. For each of these fields I need to create a function and store the value in a variable or is there a better way?
My actual code:
var email = driver.findElement(By.name('email'));
email.sendKeys('info#domain.com');
email.getAttribute("value").then(function(email_text) {
var email = email_text;
});
Cheers,
Rafael
If I understand correct, the process looks like you should fill some fields, remember their values and check values after the form has been submitted.
There is no one standard decision for tasks like this, it depends on developer.
So, we know which values we need and can store it for example in map
{
'email':'example#email.com',
'telephone':111222333
}
Key is name for finding element, value - for sendKey and checkValue methods.
You should write two methods, which will work with test data map and will fill inputs and check values in cycle by map keys.
Do you mean you want to do this as an array?
// you can represent each field as an object
var fields = [
{ elementName: 'email', expectedText: 'info#domain.com' },
{ elementName: 'password', expectedText: 'bla bla bla' }
];
// sendKeys to each field with the specified text
fields.forEach(function(field) {
browser.driver.findElement(by.name(field.elementName)).sendKeys(field.expectedText);
});
// to get all the field text (from promises) and store it as an array
browser.controlFlow().execute(function() {
var textArray = [];
fields.forEach(function(field) {
browser.driver.findElement(by.name(field.elementName)).getAttribute('value').then(function(actualText) {
textArray.push({elementName: field.elementName, actualText: actualText});
});
});
return textArray;
}).then(function(storedTextArray) {
// do something with the stored text array here
});
I have a table in my Parse database with columns validFrom and uniqueId. There can be multiple records with the same uniqueId (like a name)
What query do I have to use to get the items with the latest validFrom for a given set of uniqueIds? I tried the following but this limits my search to 1 item for the entire set rather than 1 item per unique_id record:
var UpdateObject = Parse.Object.extend("UpdateObject");
var query = new Parse.Query(UpdateObject);
query.containedIn("unique_id", uniqueIdsArray).select('status', 'unique_id').descending("validFrom").limit(1);
The query semantics are limited, so the only approach is to query for a superset and manipulate the result to what you need. This is better done on the server to limit the transmission of extra objects.
Big caveat: did this with pencil and paper, not a running parse.app, so it may be wrong. But the big idea is to get all of the matching objects for all of the uniqueIds, group them by uniqueId, and then for each group return the one with the maximum validFrom date...
function updateObjectsInSet(uniqueIdsArray ) {
var query = new Parse.Query("UpdateObject");
// find all of the UpdateObjects with the given ids
query.containedIn("unique_id", uniqueIdsArray);
query.limit(1000);
return query.find().then(function(allUpdates) {
// group the result by id
var byId = _.groupBy(allUpdates, function(update) { return update.get("unique_id"); });
// for each group, select the newest validFrom date
return _.map(byId, function (updates) {
_.max(updates, function(update) { return -update.get("validFrom").getTime(); });
});
});
}
To place this in the cloud, just wrap it:
Parse.Cloud.define("updateObjectsInSet", function(request, response) {
updateObjectsInSet(request.params.uniqueIdsArray).then(function(result) {
response.success(result);
}, function(error) {
response.error(error);
});
});
Then use Parse.Cloud.run() from the client to call it.
Update: (The answer below was correct and helped to change the code, the issue now lies with mongoose and mongoDB, where mongoose appears to attempt a writing creating the collection but not actually writing the documents)
Why can't I bind the item that is nested in the req.body.goe.coordinates.0 or .1 The req.body.geo.coordinates is showing as an object which has an array of two numbers (coordinates). So far I can get the server to write all the other fields accept the geo field.
I assumed i could use req.body.geo.coordinates.0 because zero would be the first number in the array, right? i must be thinking of the req.body incorrectly and trying to access it in a manner that isn't correct.
How can I access these coordinates so that I can place them in the correct spot in the mongoose schema. I tried loading it as a whole object but mongoose wouldn't write that geo portion and would use the default.
As always thank you for you responses.
relevant part of mongoose schema:
var itemsSchema = new Schema({item:{
user_name: {type: String, default: 'badboy for life'},
city: {type:String},
geo:{
gtype: {type:String, default: "Point"},
coordinates: {longitude: {type:Number, default: -97.740678},
latitude: {type:Number, default: 30.274026 }},
},
title: {type: String, match: /[a-z]/},
desc: {type:String},
cost:{type: Number, index: true},
//Still can't get the image to load into mongoose correctly I'm assuming
// i'm doing it wrong but that's a question for another day.
//image: {
// mime: {type:String},
// bin: Buffer,
// }
}});
Express app.post that handles the post to the mongoDB server. It currently spits out the default values.
app.post('/js/dish', parser, function(req, res) {
var a = req.body.user_name;
var b = req.body.title;
var c = req.body.cost;
var d = req.body.ingdts;
var e = req.body.location;
var f = req.body.geo.coordinates.0;
var g = req.body.geo.coordinates.1;
// create an object, information comes from AJAX request from Angular
console.log(req.body.geo["coordinates"]);
console.log("hey the object request has this in it: "+ req, req.method);
Item.create({"item.user_name":a, "item.title": b, "item.cost": c, "item.desc": d, "item.city": e, "item.geo.coordinates.latitude":f,"item.geo.coordinates.longitude":g},
function(err, item) {
if (err){
res.send(err);
}else{
// get and return all the items after you create another
getItems(res);
}
});
Map Service in Angular which gets and Sets GPS
(function(){
var mapSrvc = angular.module("mapService",[]);
console.log('map factory baby!')
var position = [];
var mapPopulation = [];
mapSrvc.service('Maping',['$http',function(){
return{
getUserGPS:function(){
return position;
},
setUserGPS:function(lat,long){
return position = [lat,long];
},
getMapPop:function(dbLocs){
return mapPopulation = dbLocs;
}
}
}])
})();
The Angular control which is setting the value and sending it to the express portion of the app
$scope.createItem = function(item){
if($scope.items.text != false){
var itemCord = Maping.getUserGPS();
$scope.items={
user_name: item.user_name,
title: item.title,
cost: item.cost,
location: item.location,
ingdts: item.ingdts,
geo:{coordinates:{longitude:itemCord[1],latitude:itemCord[0]}}
}
console.log("breadcrumb to see if item was defined: ",$scope.items)
$scope.loading = true;
Items.create($scope.items)
.success(function(data){
Items.get()
.success(function(data){
$scope.items= data;
$scope.loading = false;
console.log(data);
})
.error(function(err){
console.log('Error: ' + err);
});
$scope.loading=false;
$scope.items= {};
$scope.items= data;
})
.error(function(err){
console.log('Error: ' + err);
});
}
};
Your coordinates object in your schema is an object literal, not an array.
Array elements can be accessed by index, but not in the way you assumed. In an array, you'd access elements with bracket notation so consider the following:
var foo = ["bar", "baz"];
console.log(foo[0]);
For an object however, unless you're actually grabbing keys named 0 and 1, it doesn't work in the same way.
If you want to access longitude and latitude in the bracket notation above, the coordinates object in your Schema would have to be an array. Although, that kind of makes naming the values and putting them in the longitude and latitude objects kind of useless. Talking about this part here (I took out the comment to make it easier to follow):
coordinates: {longitude: {type:Number, default: -97.740678}, latitude: {type:Number, default: 30.274026 }},
You have another option which may be more suitable. Just access the values in the coordinates object by key. Do you know how object literals work in JavaScript? Instead of accessing values by number (or index) you access them by the names you gave them (or the keys). So you'd instead access the values like this:
var f = req.body.geo.coordinates.longitude;
var g = req.body.geo.coordinates.latitude;
... because that's what you named them.
To simply things, to access by index, either name the keys 0 and 1 instead of longitude and latitude in the coordinates object (you probably should not do this) or make the coordinates object into an array like in the above example with foo, or access the keys by the names that you gave them like that directly above.
I Have a document like this
...
"users" : [
{
"name":"Bob"
},
{
"name":"Foo"
},
{
"name":"Bar"
},
{
"name":"Boo"
}
]
...
And I want Find the index of Bar
db.coll.find({"users.name":"Bar"})
Can I retrieve the Index of Bar inside Users array? (in this case : 2)
I really don't think the question you are asking leads to the actual answer that you want, but I'll run through a few things to clear up some misconceptions.
Operations such as .find() only returns the "fields present" in the document. It does not create "new results" in any way. The only present exception is the $meta operation which currently only has "textScore" when used with the $text operator for a text search.
There is a positional $ operator, which does "hold" the "matched" position of the first matched array element. But this value itself cannot be "projected" and is only used as a placeholder in order to return an array element at that matching position:
db.collection.find({ "users.name": "Bar" }, { "users.$": 1 })
Which just returns the matching element from the array and no other elements.
In order to get the actual matching position you generally need to inspect the array in code in order to find the matching index position. So retrieve the document and then inspect the array to find the matching index.
If you want to do this over multiple documents then you pretty much do the same thing wrapped in a mapReduce operation. For a full example working with mongoose:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var userFieldSchema = new Schema({
name: String
},{ "_id": false });
var userSchema = new Schema({
users: [userFieldSchema]
});
var User = mongoose.model( "User", userSchema, "users" );
var value = "Bar";
var o = {};
o.map = function() {
emit( this._id, this.users.map(
function(x) { return x.name == value }).indexOf(true)
);
};
o.reduce = function(){};
o.query = { "users.name": value };
o.scope = { value: value };
User.mapReduce(o, function(err,results) {
if ( err ) throw err;
console.log( results );
});
Where the results returned are the _id of the documents matching the condition and the corresponding matching "index" value from the array being tested.
Only operations such as mapReduce and aggregate actually "change" the content of the documents they are working on in the returned result. So there is no present implementation that allows this to be possible with operations such as .find().
I need to connect 2 queries in Parse.com with an and, my code is:
var queryDeseo1 = new Parse.Query(DeseosModel);
queryDeseo1.equalTo("User", Parse.User.current());
queryDeseo1.equalTo("Deseo", artist);
queryDeseo1.find({...
The result of the .find is all the objects with User = Parse.User.current()) and all the objects with Deseo = artist but I want the objects with the two queries together:
User = Parse.User.current()) and Deseo = artist
You've actually got it setup correctly to do an AND query. The problem (assuming that your data structure is setup properly) is that your User field is a Pointer to the User table. Therefore, you need to query for a User equal to the pointer, as opposed to a User equal to Parse.User.current() which will return a string. Something like the following:
var userPointer = {
__type: 'Pointer',
className: 'User',
objectId: Parse.User.current().id
}
queryDeseo1.equalTo('User', userPointer);