I have the following model stored in mongodb:
{
"_id": (MongoId)
"user": "X",
"field-name-1":{
"obj-1": 12345,
"obj-2": 54321,
"obj-3": 67890,
(...)
},
"field-name-2:{
"obj-1": {"foo":"bar", "bar":"foo"},
"obj-2": {"foo":"bar2", "bar":"foo2"},
(...)
}
}
How do I find the ocurrences that contains more than 5 objects inside the "field-name-1"? Is it the same for "field-name-2"?
I can't use a variable to count the amount of objects because I upsert values inside the "field-name-1"/"field-name-2" constantly.
Thanks.
Already tried (without success):
db.summoners.find({$where: "this.['field-name-1'].length > 5"})
db.summoners.find({$where: "['field-name-1'].length > 5"})
$where should be qualified in this case:
function findMyDocument(key, value) {
var f = this[key];
if (typeof f != "object" || typeof value != "number") {
return false;
}
var count = 0;
for (var x in f) {
if (++count > value) {
return true;
}
}
return false;
}
// store above function to database for invoking
db.system.js.insert({_id:"findMyDocument", value: findMyDocument});
// apply here
db.summoners.find({$where: "findMyDocument.call(this, 'field-name-1', 5);"});
db.summoners.find({$where: "findMyDocument.call(this, 'field-name-2', 5);"});
Related
I've a fixed list reservedGuest. After checking the condition in for loop I want to update the seats if the membership date has expired. The list is not updating. The code is as follows. PS. The List is filled through API on init().
class MyClubController extends GetxController {
List goldLane = List.filled(3, null, growable: false);
void _alterLanesOnContractEnds() {
for (var i in goldLane) {
print("\n\n I: $i");
if (i == null ||
DateTime.parse(i['contractEnds']).isBefore(
DateTime.now(),
)) {
i = null;
print('Can be removed');
} else {
print('Cannot be removed');
}
}
update();
}
}
A for-in loop will not allow you to reassign elements of the List. When you do:
for (var i in goldLane) {
// ...
i = null;
}
you are reassigning what the local i variable refers to, not mutating the goldLane List.
You instead can iterate with an index:
void _alterLanesOnContractEnds() {
for (var i = 0; i < goldLane.length; i += 1) {
var element = goldLane[i];
print("\n\n I: $element");
if (element == null ||
DateTime.parse(element['contractEnds']).isBefore(
DateTime.now(),
)) {
goldLane[i] = null;
print('Can be removed');
} else {
print('Cannot be removed');
}
}
update();
}
You can just create a new List where unqualified guests are nullified. For example,
void _alterLanesOnContractEnds() {
goldLane = goldLane.map(
(guest) => guest == null || DateTime.parse(guest['contractEnds']).isBefore(DateTime.now()) ? null: guest
).toList(growable: false);
update();
}
You should not and cannot modify a list while iterating with its iterator.
Elaborated by Jamesdlin,
Modifying the elements of a List while iterating is fine. Modifying
the length of the List while iterating is not, but that won't be a
problem for a non-growable List.
The bottom line is you should not mutate the size of the list while iterating.
I solved it by using
goldLane.forEach(
(element) {
print('\n\n ELEMENT: $element');
if (element == null ||
DateTime.parse(element['contractEnds']).isBefore(
DateTime.now(),
)) {
int ix = goldLane.indexWhere(
(element) => element != null
? DateTime.parse(element['contractEnds']).isBefore(
DateTime.now(),
)
: true,
);
goldLane[ix] = null;
} else {
print('Cannot be removed');
}
},
);
Yet I'll test the other answers. Thank You.
I have a MEAN app, and I have lots of dates stored in the mongodb, the clock is changing in the UK on 27th October, so all of the dates stored in the db need to have one hour added.
I wouldn't like to loop through all docs in the db and add an hour to its dates, I'd prefer that to be dynamic, so I'm trying to implement a query hook to check each date on the incoming docs and the timezone offset attached in the doc to add/subtract the timezone offset.
The problem is that I'd like the loop on the incoming docs to dynamically identify where the dates are, which will be sometimes on the root of the doc, buried inside an object or an array, which I'm having a hard time to model the loop to check all of that.
I'm using functions to check if the incoming object is a date, an object or an array, but mongoose is adding a bunch of objects/functions that are hindering the operation, so I'm getting RangeError: Maximum call stack size exceeded
const config = require('../config/environment');
var UK_TIMEZONE_GMT_OFFSET = config.UK_TIMEZONE_GMT_OFFSET || 0; // should check if the offset is the same as in each document in the db, if it doesn't match then I'll subtract the offset.
const mongoose = require('mongoose');
const exec = mongoose.Query.prototype.exec;
const Q = require('Q');
mongoose.Query.prototype.exec = function () {
var d = Q.defer();
var p = exec.apply(this, arguments);
if (p) p.then(function (rs) {
var mod;
try {
mod = fixDates(rs);
} catch (err) {
console.log(err, rs)
};
d.resolve(mod);
}, d.reject);
return d.promise;
}
function fixDates(rs) {
if (isArray(rs)) {
rs.forEach(function (r, i) {
rs[i] = fixDates(r);
})
} else if (isObject(rs)) {
for (var key in rs) {
var val = rs[key];
if (isObject(val)) console.log('isobject', isObject(val), val);
// the '_id' of the document is considered an object
// also some stuff like Schema, NativeCollection ... are objects as well
// rs[key] = fixDates(val); // this line causes problems
}
} else if (isDate(rs)) {
// modify the date if necessary ..
// Check the timezone offset of the document vs the global timezone offset
of the system then add/subtract the difference
}
return rs;
}
function isDate(obj) {
return obj instanceof Date;
}
function isObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
function isArray(obj) {
return Array.isArray(obj);
}
I need better methodology to deal with mongoose returned object in order to loop through all documents and deeply find the dates and modify them.
I updated the recurring function to invoke model.toObject if exists and apply the update the date fields, while still keeping the model class
function recur(rs, docTimezone) {
if (isArray(rs)) {
rs.forEach(function (r, i) {
rs[i] = recur(r, docTimezone);
})
} else if (isObject(rs)) {
if (rs.toObject) {
return updateModel(rs, recur(rs.toObject(), docTimezone))
}
Object.keys(rs).forEach(function (key) {
var val = rs[key];
rs[key] = recur(val, docTimezone !== undefined ? docTimezone : rs.usedTimezoneGMTOffset); // usedTimezoneGMTOffset if exists on the doc
})
} else if (isDate(rs)) {
// modify the date if necessary ..
rs = alignTimezone(rs, docTimezone);
}
return rs;
}
function updateModel(model, updates) {
var key, val;
for (key in updates) {
val = updates[key];
if (val !== void 0 && key !== '_id') {
model[key] = val;
}
}
return model;
}
I'm having trouble with office js and processing a list of items with lookup codes and replacement values for the header and footer. I've got the body working just not the header/footer. I'm getting this error:0x800a139e - JavaScript runtime error: The property 'items' is not available. Before reading the property's value, call the load method on the containing object and call "context.sync()" on the associated request context. As you can see I do call load and sync before trying to access the results.
function mergeHeader(documentFieldKeys) {
if (documentFieldKeys.length > 0)
Word.run(function(context) {
var key = documentFieldKeys.shift();
var mySections = context.document.sections;
context.load(mySections, 'body/style');
return context.sync().then(function() {
for (var i = 0; i < mySections.items.length; i++ ) {
findAndReplace(key, context, mySections.items[i].getHeader("primary"));
}
return context.sync().then(function() {
return mergeHeader(documentFieldKeys);
})
.then(context.sync);
});
});
}
function findAndReplace(key, context, body) {
var results = body.search(key.Code, { matchWholeWord: false, matchCase: false });
context.load(results);
return context.sync().then(function() {
if (results.items.length > 0 && key.Value === "") {
missingFields.push(key.Description);
} else {
for (var i = 0; i < results.items.length; i++) {
results.items[i].insertText(key.Value, "replace");
}
}
})
.then(context.sync);
}
Any help would be appreciated.
Add
context.load(mySections, 'items');
or
mySections.load('items');
It appears sap.ui.model.Sorter doesn't sort ISO-8859-1 characters correctly.
Below is an example where we create a list with one item pr character in the Norwegian alfabet. The output of this is not in the correct order, instead the order is "AÅÆBCDEFGHIJKLMNOØPQRSTUVWXYZ".
The expected results is the same order as when the alfabet variable is declared: "ABCDEFGHIJKLMOPQRSTUVWXYZÆØÅ"
How can we sort the model correctly?
JSBIN: https://jsbin.com/xuyafu/
var alfabet = "ABCDEFGHIJKLMOPQRSTUVWXYZÆØÅ"
var data = [];
for(var i=0; i< alfabet.length; i++){
data.push ({value:alfabet.charAt(i)});
}
var modelList = new sap.ui.model.json.JSONModel(data);
sap.ui.getCore().setModel(modelList);
var oSorter = new sap.ui.model.Sorter("value", null, null);
// Simple List in a Page
new sap.m.App({
pages: [
new sap.m.Page({
title: "Sorting with norwegian characters",
content: [
new sap.m.List("list", {
items: {
path: '/',
template: new sap.m.StandardListItem({
title: '{value}'
}),
sorter: oSorter
}
})
]
})
]
}).placeAt("content");
Based on the input from the comments on the question, it is straight forward to override the sorting function fnCompare to get the right order
var oSorter = new sap.ui.model.Sorter("value", null, null);
oSorter.fnCompare = function (a, b) {
if (a == b) {
return 0;
}
if (b == null) {
return -1;
}
if (a == null) {
return 1;
}
if (typeof a == "string" && typeof b == "string") {
return a.localeCompare(b, "nb");
}
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
Here "nb" is the locale the sort is done with
When I write in my mongoDB with mongoose the operation is treated with success, my document is saved, but there is also all kind of weird other sutff written down. It seems to be mongoose code. What could cause this?
I add stuff in a specific array with:
resultReference.ref[arrayLocation].allEvents.push(theEvent);
{id: 11, allEvents: [] } is the structure of a ref element, and I push theEvent in the allEvents array. I then resultReference.save()
I use express, mongoose and mongoHQ for database. I tried on a local mongo server, and this annoyance is still there. I've print in my console the document to write before save() and non of this weird code is there.
{
id 11
allEvents
[
0
{
_events
{
maxListeners 0
}
_doc
{
_id {"$oid": "4eb87834f54944e263000003"}
title "Test"
allDay false
start 2011-11-10 13:00:00 UTC
end 2011-11-10 15:00:00 UTC
url "/test/4eb87834f54944e263000002"
color "#99CCFF"
ref "4eb87834f54944e263000002"
}
_activePaths
{
paths
{
title "modify"
allDay "modify"
start "modify"
end "modify"
url "modify"
color "modify"
ref "modify"
}
states
{
init
{ }
modify
{
title true
allDay true
start true
end true
url true
color true
ref true
}
require
{ }
}
stateNames
[
0 "require"
1 "modify"
2 "init"
]
}
_saveError null
_validationError null
isNew true
_pres
{
save
[
0
function (next) {
// we keep the error semaphore to make sure we don't
// call `save` unnecessarily (we only need 1 error)
var subdocs = 0
, error = false
, self = this;
var arrays = this._activePaths
.map('init', 'modify', function (i) {
return self.getValue(i);
})
.filter(function (val) {
return (val && val instanceof DocumentArray && val.length);
});
if (!arrays.length)
return next();
arrays.forEach(function (array) {
subdocs += array.length;
array.forEach(function (value) {
if (!error)
value.save(function (err) {
if (!error) {
if (err) {
error = true;
next(err);
} else
--subdocs || next();
}
});
});
});
}
1 "function checkForExistingErrors(next) {
if (self._saveError){
next(self._saveError);
self._saveError = null;
} else {
next();
}
}"
2 "function validation(next) {
return self.validate.call(self, next);
}"
]
}
_posts
{
save
[ ]
}
save
function () {
var self = this
, hookArgs // arguments eventually passed to the hook - are mutable
, lastArg = arguments[arguments.length-1]
, pres = this._pres[name]
, posts = this._posts[name]
, _total = pres.length
, _current = -1
, _asyncsLeft = proto[name].numAsyncPres
, _next = function () {
if (arguments[0] instanceof Error) {
return handleError(arguments[0]);
}
var _args = Array.prototype.slice.call(arguments)
, currPre
, preArgs;
if (_args.length && !(arguments[0] === null && typeof lastArg === 'function'))
hookArgs = _args;
if (++_current < _total) {
currPre = pres[_current]
if (currPre.isAsync && currPre.length < 2)
throw new Error("Your pre must have next and done arguments -- e.g., function (next, done, ...)");
if (currPre.length < 1)
throw new Error("Your pre must have a next argument -- e.g., function (next, ...)");
preArgs = (currPre.isAsync
? [once(_next), once(_asyncsDone)]
: [once(_next)]).concat(hookArgs);
return currPre.apply(self, preArgs);
} else if (!proto[name].numAsyncPres) {
return _done.apply(self, hookArgs);
}
}
, _done = function () {
var args_ = Array.prototype.slice.call(arguments)
, ret, total_, current_, next_, done_, postArgs;
if (_current === _total) {
ret = fn.apply(self, args_);
total_ = posts.length;
current_ = -1;
next_ = function () {
if (arguments[0] instanceof Error) {
return handleError(arguments[0]);
}
var args_ = Array.prototype.slice.call(arguments, 1)
, currPost
, postArgs;
if (args_.length) hookArgs = args_;
if (++current_ < total_) {
currPost = posts[current_]
if (currPost.length < 1)
throw new Error("Your post must have a next argument -- e.g., function (next, ...)");
postArgs = [once(next_)].concat(hookArgs);
return currPost.apply(self, postArgs);
}
};
if (total_) return next_();
return ret;
}
};
if (_asyncsLeft) {
function _asyncsDone (err) {
if (err && err instanceof Error) {
return handleError(err);
}
--_asyncsLeft || _done.apply(self, hookArgs);
}
}
function handleError (err) {
if ('function' == typeof lastArg)
return lastArg(err);
if (errorCb) return errorCb.call(self, err);
throw err;
}
return _next.apply(this, arguments);
}
errors null
}
]
}
]
The reason this happened is because I didnt save my schema in mongoose in the proper order. This would mean declaring your child schema before a parent to get proper behavior.