2014年3月2日 星期日

[Javascript] JQuery UI - Uncaught TypeError: Object function (a,b){return new n.fn.init(a,b)} has no method 'curCSS' @ JQuery 1.11.0

最近在用某個 open source 時,他的開發是用 jQuery 1.5.x 系列 ,但一用最新版 jQuery 1.11.0 時,就會蹦出這個錯誤訊息,找了一下應該是用了 non-stable  API 吧?

解法:

<script type="text/javascript" src="/js/jquery-1.11.0.min.js"></script>
<script>
    jQuery.curCSS = jQuery.css;
</script>


雖然解法不是很好 XD 但對於使用 open source 而言,可以降低維護問題,也算是無可厚非的吧。

2014年2月28日 星期五

MongoDB 開發筆記 - 使用 find / aggregate: $match 找尋必有或必無某屬性(property/element/field)的資料

話說 MongoDB 真是越用越順手,也唯有這樣才能體會大家為何對他驚歎 :P 在處理資料時,由於 schema free style,有時分析資料時,希望每筆資料都要有某個屬性才來處理,或是資料不能有某個屬性:

db.collection.find( { property: {$ne: null }} )
db.collection.find( { property: null} )


如果 property 的內容物是一個 array,如 { "property":[ ... ] } ,這時想要要求此 array 個數要大於 1 時,則可以改用 "$where" 語法(據說效率較慢,但 it's works !):

db.collection.find( { "$where": "this.property && this.property > 1" } )

然而,在 aggregate 的 $match 卻無法使用 "$where" 語法,可惜了點,會有以下錯誤訊息:

failed: exception: $where is not allowed inside of a $match aggregation expression

此外,就算分析出來,還是有要分析到 array 裡頭項目,又發現 aggregate 有 $unwind 的功能!效果就是幫你把 array 裡頭的資料一筆筆輸出:

db.collection.aggregate([
{
$match: {
property: { $ne : null }
}
},
{
$unwind: "$property"
},
{
$group: {
_id: "$property.name",
count: {
$sum: 1
}
}
}
])


單筆資料如:

{
"id": "client",
"date": "date",
"property":
[
{ "name": "ios", "version": 1 } ,
{ "name": "android", "version": 1 } ,
{ "name": "ios", "version": 2 }
]
}


假設資料就上述一筆,透過 aggregate $unwind 總輸出會是 property.length 個數:

{ "id": "client", "date": "date", "name": "ios", "version": 1 }
{ "id": "client", "date": "date", "name": "android", "version": 1 }
{ "id": "client", "date": "date", "name": "ios", "version": 2 }

2014年2月27日 星期四

[Linux] 申請 Godaddy Wildcard Certificate 和設定 Nginx Web Server @ Ubuntu 12.04

ssl-01

在 Godaddy 購買 Domain Name,接著就來申請 SSL 憑證,依據需求就買了 wildcard certificate 版本。自簽憑證的經驗不少,但是還沒設定過 wildcard 版本 XD

ssl-03

首先先完成 Godaddy 的購買,可以參考 [筆記] SSL 憑證購買記

接著,很快就進入 Godaddy SSL 設定界面,並要求貼上 Certificate Signing Request(CSR) 資料。這邊需留意的是建立 CSR 的過程中,以前在 Common Name 總是輸入完整的 hostname (如 blog.changyy.org),現在要改輸入成 * 開頭(如: *.changyy.org),算是關鍵之處。

$ openssl req -new -newkey rsa:2048 -nodes -keyout wildcard.domainname.key -out wildcard.domainname.csr

最後再把 wildcard.domainname.csr 打開後,複製內文貼上即可進行。

ssl-04

由於是購買 wildcard 版本,如果 common name 不是輸入 * 開頭,會看到錯誤訊息,也是個不錯的防呆。

ssl-06

接著,再切換到下載頁面,就可以挑選屬於自己的 web server 資料。

對於 nginx 的部分,下載回來共有兩個 csr 檔案,對 apache web server 而言,可以分開設定剛剛好,但 nginx 只有 ssl_certificate 跟 ssl_certificate_key 兩個啊,因此,只要把 godaddy 給你的兩個 crt 串起來使用即可:

$ cp xxxx.crt hostname.crt
$ cat gd_bundle-g2-g1.crt >> hostname.crt


接著在 nginx 設定檔中,把 ssl_certificate 填 hostname.crt 而 ssl_certificate_key 則是最早建立 crt 的 key (此例 wildcard.domainname.key)

2014年2月26日 星期三

MongoDB 開發筆記 - Aggregate 之 Group BY Timestamp / GROUP BY ObjectID getTimestamp @ MongoDB Server v2.4.9

上回看文件時,上頭說系統預設 ObjectID(_id) 中,已經有時間戳記了,並且建議不需要額外在儲存一個時間:
ObjectId is a 12-byte BSON type, constructed using:
a 4-byte value representing the seconds since the Unix epoch,
a 3-byte machine identifier,
a 2-byte process id, and
a 3-byte counter, starting with a random value.
開發環境:MongoDB Server v2.4.9
目標:SELECT `timestamp`, count(*) AS count FROM `test` GROUP BY `timestamp`;

儘管 ObjectID 有提供 _id.getTimestamp() 方式存取時間,但是在用 aggregate 時卻無法動態取用($year, $month, $dayOfMonth),如:

mongodb> db.test.aggregate({
$group:{
_id: {
year: { $year: "$_id.getTimestamp()" } ,
month: { $month: "$_id.getTimestamp()" } ,
day: { $dayOfMonth: "$_id.getTimestamp()" }
},
count: {
$sum:1
}
}
})
mongodb> aggregate failed: {
        "errmsg" : "exception: can't convert from BSON type EOO to Date",
        "code" : 16006,
        "ok" : 0
}


看來在 v2.4.9 版的應用時,還是需要建立一個 timestamp 出來,然而 db.collection.update 無法拿 document 自身資料來更新,例如從 ObjectID 抽出時間來用:

mongodb> db.test.update({timestamp: null }, { $set : { timestamp: _id.getTimestamp() } }, {multi:true})
ReferenceError: _id is not defined


需要改用 forEach 來一筆筆更新:

mongodb> db.test.find({timestamp:null}).snapshot().forEach(
function (item) {
item.timestamp = item._id.getTimestamp();
//db.test.save(item);
db.test.update(
# query
{
'_id': item['_id']
},
# update
{
'$set':
{
'timestamp': item['timestamp']
}
},
upsert=False, multi=False
);
}
)


接著終於可以 GROUP BY DATE 了 Orz

mongodb> db.test.aggregate(
{
$group:{
_id: {
year: { $year: "$timestamp" } ,
month: { $month: "$timestamp" } ,
day: { $dayOfMonth: "$timestamp" }
},
count: {
$sum:1
}
}
}
)
{
        "result" : [
                {
                        "_id" : {
                                "year" : 2014,
                                "month" : 2,
                                "day" : 22
                        },
                        "count" : 23
                },
                {
                        "_id" : {
                                "year" : 2014,
                                "month" : 2,
                                "day" : 21
                        },
                        "count" : 15
                },
                {
                        "_id" : {
                                "year" : 2014,
                                "month" : 2,
                                "day" : 20
                        },
                        "count" : 200
                }
        ],
        "ok" : 1
}

[Linux] 使用 Node.js 與 MongoDB 溝通與帳號認證 @ Ubuntu 12.04

透過 apt-get 安裝 node.js:

$ sudo apt-get install python-software-properties
$ sudo add-apt-repository ppa:chris-lea/node.js
$ sudo apt-get update
$ sudo apt-get install nodejs


建立 project:

$ cd project
$ npm install mongodb
$ vim test.js
var Db = require('mongodb').Db,
        MongoClient = require('mongodb').MongoClient;

var db_host = 'localhost';
var db_port = 27017;
var auth_db = 'admin';
var auth_name = 'account';
var auth_pass = 'password';

MongoClient.connect("mongodb://"+auth_name+":"+auth_pass+"@"+db_host+":"+db_port, function(err, db) {
        console.log(err);
        console.log(db.databaseName);
        db.close();
});

MongoClient.connect("mongodb://"+db_host+":"+db_port, function(err, db) {
        db.authenticate(auth_name, auth_pass, function(err, ret) {
                console.log(err);
       console.log(db.databaseName);
                console.log(ret);
       db.close();
        });
});
$ node test.js
Failed to load c++ bson extension, using pure JS version
null
admin
null
admin
true


以上為兩種跟 mongodb 進行認證的方式,一種是寫在 URI 中,另一種則是透過 db.authenticate 方式,至於這份程式的輸出不見得 "true" 是在最後一列,也有可能在第三列,這是因為 node.js async 架構關係,在這份 code 中不保證哪個 function 先跑。

如果 mongodb 本身要求認證,而未認證則會有錯誤訊息:

{ [MongoError: unauthorized] name: 'MongoError', ok: 0, errmsg: 'unauthorized' }

比較疑惑的地方是對於 auth_db 的部分,之前在用 pymongo 時,或是直接用 mongo 指令時,必須透過指定 authenticationDatabase 才能通過認證,但在 node.js 中,似乎沒有問題?再來摸看看好了。