First of, I'm quite new to mongodb. Here's my question I've not been able to find a solution to.
Let's say I have 3 different collections.
mongos> show collections
collectionA
collectionB
collectionC
I want to create a script that iterates over all collections ind this database and find the last inserted timestamp in each of these collections. Here's what works inside mongos.
var last_element = db.collectionA.find().sort({_id:-1}).limit(1);
printjson(last_element.next()._id.getTimestamp());
ISODate("2014-08-28T06:45:47Z")
1. Problem (Iterate over all collections)
Is there any possibility to to sth. like.
var my_collections = show collections;
my_collections.forEach(function(current_collection){
print(current_collection);
});
Problem here, the assignment for my_collections does not work.
I get SyntaxError: Unexpected identifier. Do I need to quote the 'show' statement ? Is it even possible ?
2. Problem (storing collection in js var)
I can workaround Problem 1 by doing this:
var my_collections = ["collectionA", "collectionB", "collectionC"];
my_collections.forEach(function(current_collection){
var last_element = db.current_collection.find().sort({_id:-1}).limit(1);
print(current_collection);
printjson(last_element.next()._id.getTimestamp());
});
The last_element.next() produces the following error:
error hasNext: false at src/mongo/shell/query.js:124
It seems that last_element isn't saved correctly.
Any suggestions on what I'm doing wrong??
UPDATE
Neils answer lead me to this solution. In addition to his code I had to check if the function getTimestamp really exist. For some 'virtual' collections there seem to be no _id property.
db.getCollectionNames().forEach(function(collname) {
var last_element = db[collname].find().sort({_id:-1}).limit(1);
if(last_element.hasNext()){
var next = last_element.next();
if(next._id !== undefined && typeof next._id.getTimestamp == 'function'){
printjson(collname + " >> "+next._id.getTimestamp());
}else{
print(collname + " undefined!! (getTimestamp N/A)")
}
}
});
There is the db.getCollectionNames() helper method that does this for you. You can then implement your code:
db.getCollectionNames().forEach(function(collname) {
// find the last item in a collection
var last_element = db[collname].find().sort({_id:-1}).limit(1);
// check that it's not empty
if (last_element.hasNext()) {
// print its timestamp
printjson(last_element.next()._id.getTimestamp());
}
})
You probably also want a .hasNext() check in there to cater for possible empty collections.
Rename the collection name present in all the records using the following script:
db = db.getSiblingDB("admin");
dbs = db.runCommand({ "listDatabases": 1 }).databases;
dbs.forEach(function(database) {
db = db.getSiblingDB(database.name);
db.currentname.renameCollection("newname");
});
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 9 months ago.
Improve this question
There are a couple of similar queries here about the IndexOf function, but I'm reaching out because although the answers provided have been helpful, none of them have solved the issue.
I have a (very) large 2d array from a spreadsheet of names vs id codes. I read these values in apps script into an array (rIdr in the snippet below).
I then build 2x one-dimensional arrays so that I can use IndexOf to search for a name in the first array then use the returned index it to pull out the value from the second array.
var keys=[]; var vals=[];
//build key-val lookup arrays
for (var i = 0; i < rIdr.values.length; i++){
var k = rIdr.values[i][0].toString()
keys[i]=k
var v = rIdr.values[i][1].toString()
vals[i]=k
}
The name I'm looking for is obtained from a JSON which is populated elsewhere. I iterate over the names in this object, looking for them in my key and val arrays:
jsonobj.data.forEach(function(value) {
var idx = keys.indexOf(value.first_names_txt + " " + value.last_name_txt)
var id = -1;
if (idx > -1){id = vals[idx]}
Logger.log(value.first_names_txt + " " + value.last_name_txt + " " + id)
});
I've verified that both the name i'm pulling out of the JSON object as well as the elements of the keys array are String types. I've seen in the object inspector that the keys array is an array of strings (not, for example, an array of array objects).
Try as I might, i can't get IndexOf to return anything other than -1.
Even if I explicitly look for a name which I know is in there (and actually is a copy paste of the name as it's written on the sheet that I'm pulling values from), I still get -1 returned
var test
test = keys.indexOf("Joe Bloggs")
I'm tearing my hair out here. I don't want to write a separate function to match a name in the keys array, because I'll either need to pass in the full keys array as an argument, or make it a global variable - neither of which i want to do for various reasons.
Can anyone help with why IndexOf doesn't work here?
And if this is an issue that won't go away, is there a way to write my own search function which avoids passing large arrays around or declaring them as global variables?
Thanks all in advance
Description
I've constructed a spreadsheet sheet using the names from the json data file, randomized the names so they are no longer in alphabetical order and then assigned an id number to each.
The sample script I've provided lists the id number for the names in the json data file. Notice I'm working with the original data array. I don't need to create key value arrays to get the result I want. And I'm not checking if a name doesn't exist in the data array.
I've truncatd the json data for brevity
Code.gs
function test_json() {
try {
let jdata = {
"type" : "entrants",
"data" : [ {
"type" : "entrant",
"id" : "en_tdgwjajthr",
"first_names_txt" : "Archie",
"last_name_txt" : "White",
"entrytype" : "et_dv8u152j",
"answers" : {
"q_wg5qq6bgvsy90rh" : "Partenza Nude-Espresso RT"
}
}, {
.
.
.
.
}, {
"type" : "entrant",
"id" : "en_8uhauoe3jo",
"first_names_txt" : "Valentijn",
"last_name_txt" : "Brax",
"entrytype" : "et_dv8u152j",
"answers" : {
"q_wg5qq6bgvsy90rh" : "Dulwich Paragon CC"
}
} ],
"has_more_bool" : false
};
let values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test").getDataRange().getValues();
jdata.data.forEach(function(value){
let key = value.first_names_txt+" "+value.last_name_txt;
let found = values.find( row => row[0] === key );
console.log("key = "+key+" id = "+found[1]);
});
}
catch(err) {
console.log(err)
}
}
Execution log (abbreviated)
10:29:05 AM Notice Execution started
10:29:06 AM Info key = Archie White id = 21
10:29:06 AM Info key = ari panzer id = 15
10:29:06 AM Info key = Daniel Mulcahy id = 5
10:29:06 AM Info key = David Streule id = 12
10:29:06 AM Info key = Dominic Bell id = 10
10:29:06 AM Info key = Euan Davies id = 14
Context
In a Firebase DB I'm storing "events" and "users". Users can have favorite events, to manage them I only store the event's id in the favorite user's DB location. So to grab favorite events informations, I need to firstable grab the event id and then go to the DB events location, to collect all the datas I need.
Problem
I would like to store in an Array all the favorite events informations (each event would be an Object with inside it : "key" : "value"), to use that Array in my HTML view and print the informations. But it doesn't work the way I coded it... :(
// This ref is too grab favorite event id (in my case only 2) in the user DB location
var refUserFavoris = firebase.database().ref().child("users/"+user.uid+"/events/favoris");
$scope.favorisTmp = $firebaseArray(refUserFavoris);
// This shows one array, with two objects (wich are my two user's favorite events) wich include ids
console.log($scope.favorisTmp);
// This is to load the objects and with the foreEach, grab there ids to use them in the next ref call
$scope.favorisTmp.$loaded().then(function()
{
angular.forEach($scope.favorisTmp, function(favoris)
{
// This shows two lines : the id of each object
console.log(favoris.$id);
// Call a new ref to reach the event informations (in a different location of the DB) using the previous id
firebase.database().ref("events/"+favoris.$id).once('value').then(function(snapshot)
{
// Attempt to store events datas for each id I have (in my case, only two)
snapshot.forEach(function(favorisSnap)
{
var favSnap = favorisSnap.val();
// This shows a lot of "undefined" lines, wich I don't want. I would like two objects, with all informations inside
console.log(favSnap.nbPersonne);
// $scope.favorisF is an Array that I would like to use in a ng-repeat to print all datas for each event
// For now this doesn't show anything
$scope.favorisF = favSnap;
});
// If using favSnap out of the previous function, I got a "favSnap" is undifined error
console.log(favSnap);
});
});
});
<ion-item ng-repeat="f in favorisF" class="item-avatar">
{{f.nbPersonne}}
</ion-item>
EDIT 1 :
I tried a new way to have my data, but a new problem came, how to fill an Array inside a loop ? I've tried "push" and "$add" methods, but no one worked. Any ideas ?
var newFav = [];
var user;
user = firebase.auth().currentUser;
var refUserFavoris = firebase.database().ref().child("users/"+user.uid+"/events/favoris");
$scope.favorisTmp = $firebaseArray(refUserFavoris);
$scope.favorisTmp.$loaded().then(function()
{
angular.forEach($scope.favorisTmp, function(favoris)
{
console.log(favoris.$id);
var refFavoris = firebase.database().ref("events/"+favoris.$id);
refFavoris.on('value', function(snap)
{
//This is where I'm trying to fill "newFav" in each steps of the loop
newFav.push(snap.val());
console.log("Scope newFav vaut :", $scope.newFav);
});
});
});
I think you made a typo here.
var refUserFavoris = firebase.database().ref("events/favoris/"+favoris.$id).once('value')
Thanks a lot Abdel, I fixed my problem :
Here is the solution
$scope.newFav = [];
console.log($scope.newFav);
$scope.favorisTmp.$loaded().then(function()
{
angular.forEach($scope.favorisTmp, function(favoris)
{
console.log(favoris.$id);
var refFavoris = firebase.database().ref("events/"+favoris.$id);
refFavoris.on('value', function(snap)
{
$scope.newFav.push(snap.val());
console.log("Scope newFav vaut :", $scope.newFav);
});
});
});
I'd like all my Firebase content to load randomly every time you refresh, but I can't seem to get all my Firebase data into a dictionary where I can randomize them.
I have a global array and I'm trying to push my files in there and then iterate through them. But Javascript thinks the array is empty because the timing is off.
var randomStore = new Array;
function homeSetup() {
if(ref.toString() == featuredRef.toString()){
addFeaturedImages();
}
console.log('randomStore length is ' + randomStore.length);
}
function addFeaturedImages(){
featuredRef.on("child_added", function(snapshot) {
var doc = {
// 'name': snapshot.key, //name is the id
'artist': snapshot.val().artist,
'author': snapshot.val().author,
'projectTitle': snapshot.val().projectTitle,
'text': snapshot.val().text
};
randomStore.push(doc);
console.log('randomStore length HERE is ' + randomStore.length);
});
}
Considering how the code is typed, I would assume that the 'randomStore length HERE is' log would be typed first, but instead I get this:
randomStore length is 0
randomStore length HERE is 1
randomStore length HERE is 2
randomStore length HERE is 3
If I got my data into a different array, then I could manipulate it to sort randomly and stuff like that, but I can't seem to get it in there properly.
You mentioned the timing is off? What did you mean by that ?
Have you heard of Javascript Promise's ?
http://www.html5rocks.com/en/tutorials/es6/promises/
This post explains promises very good. Read this very carefully, because if you are working with firebase, you will be using promises on daily!
Instead of using featuredRef.on("child_added") use featuredRef.once('value'). This should get you the whole array at once. Attach a then listener where you continue with the work of homeSetup.
function homeSetup() {
var cb = function(randomStore) {
console.log('randomStore length is ' + randomStore.length);
//....
};
if(ref.toString() == featuredRef.toString()){
addFeaturedImages(cb);
} /* else if(...) {
addFooImages(cb)
}*/
}
function addFeaturedImages(cb){
featuredRef.once("value", function(snapshot) {
//TODO: transform elements of the array?
cb(snapshot.val());
});
}
Code untested, but I should get you started.
I am having trouble getting data from the nested pointers in my array of pointers from a query. I have an array of pointers like so: [{"__type":"Pointer","className":"QuizData","objectId":"rmwJrV55c7"},{"__type":"Pointer","className":"QuizData","objectId":"2132q8i9np”}, etc…]
That QuizData class also has a column named “ad” which is a Pointer to the “Ads” class. I can get the QuizData in a query using the following include statements on my query like so:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include("quizAdArr”);
__quizAdQueueQuery.include(["quizAdArr.QuizData"]);
BUT Neither of these or both combined don’t work as when I try to get column data from the ad it’s always undefined:
__quizAdQueueQuery.include(["quizAdArr.QuizData.ad"]);
__quizAdQueueQuery.include(["quizAdArr.QuizData.Ads"]);
This is my return from that query, where the column data "mediaType" that I am trying to access is always undefined:
return __quizAdQueueQuery.first().then(function(__resultsObj)
{
__quizQueueObj = __resultsObj;
__userQuizQueueArr = __quizQueueObj.get("quizAdArr");
var __quiz;
var __ad;
var __seenAd;
var __lengthInt = __userQuizQueueArr.length;
var __mediaTypeStr = __request.params.mediaType;
var __matchedQuizzesArr = [];
for (var __i = 1; __i < __lengthInt; __i++)
{
__quiz = __userQuizQueueArr[__i];
// console.log('__quiz.get("name") = '+__quiz.get("name"));
__ad = __quiz.get("ad");
// console.log("__ad.id = "+__ad.id);
//THE MEDIA TYPE IS ALWAYS RETURNING UNDEFINED HERE!!!
console.log('__ad.get("mediaType") = '+__ad.get("mediaType")+', __mediaTypeStr = '+__mediaTypeStr);
if (__ad.get("mediaType") == __mediaTypeStr)
{
//put all matches in array to be sorted
__matchedQuizzesArr.push(__userQuizQueueArr[__i]);
console.log("__matchedQuizzesArr.length = "+__matchedQuizzesArr.length);
}
}
return __matchedQuizzesArr;
});
Thanks for any help you can give! I also posted this as a bug in the Parse/Facebook issue reporter but was redirected here, so if this is a bug I can reopen it: https://developers.facebook.com/bugs/923988310993165/
EDIT Here is the updated, working query with nested includes for clarity:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include('quizAdArr');
__quizAdQueueQuery.include('quizAdArr.ad');
This should work (you only need to list the column names):
query.include('quizAdArr.ad');
Here's why:
You're querying QuizAdQueue so you don't need to list that
The QuizAdQueue class has an array in quizAdArr so you include it: query.include('quizAdArr');
Each quizAdArr element is a QuizData with an ad so you include it: query.include('quizAdArr.ad');
The issue was that you were including QuizData which is the name of a class and not a column name
so I have a JSON object returned from a webservice. Now I want to:
get a subset which matches a categoryTitle i pass as parameter (this seems to work)
from my filtered resultset I want to get another array of objects (helpsubjects), and for each of this subjects I want to extract the SubjectTitle.
Problem: It seems my Array of HelpSubjects does not exist, but I can't figure out why and hope you could help.
Perhaps this piece of commented code makes it more clear:
$.fn.helpTopicMenu = function (data) {
that = this;
var categoryContent = contents.filter(function (el) {
return el.CategoryTitle == data.categoryTitle;
});
debug('categorys Content: ', categoryContent); //see below
var container = $('#subjectList');
var subjectList = categoryContent.HelpSubjects;
debug('Subjects in Category: ', subjectList); // UNDEFINED?!
$.each(subjectList, function (i, item) {
container.append(
$('<li></li>').html(subjectList[i].SubjectTitle)
);
});
the line debug('categorys Content: ', categoryContent); returns the following object as shown in the picutre (sadly I can't add a picture directly to the post yet, so here's the link): http://i.stack.imgur.com/0kKWx.png
so as I understand it, there IS actually a HelpSubjects-Array, each entry containing a SubjectTitle (in the picture there actually is only one entry, but I need to have the Artikel einfügen as my html.
Would be great if you can help me.
The variable categoryContent set is an array of objects.
Try debugging categoryContent[0].HelpSubjects and see if you can access the property. If so, you can also loop this array if need be.