MongoDB를 데이터 저장소로 사용하여 일종의 백그라운드 작업 대기열 시스템을 만들고 있습니다. 작업자가 작업을 처리하기 전에 MongoDB 컬렉션에 삽입물을 "듣기"하려면 어떻게해야합니까? 마지막 시간부터 변경 사항이 있는지 또는 스크립트가 삽입을 기다릴 수있는 방법이 있는지 확인하기 위해 몇 초마다 폴링해야합니까? 이것은 내가 작업중 인 PHP 프로젝트이지만 루비 또는 언어에 구애받지 않고 자유롭게 대답하십시오.
MongoDB를 데이터 저장소로 사용하여 일종의 백그라운드 작업 대기열 시스템을 만들고 있습니다. 작업자가 작업을 처리하기 전에 MongoDB 컬렉션에 삽입물을 "듣기"하려면 어떻게해야합니까? 마지막 시간부터 변경 사항이 있는지 또는 스크립트가 삽입을 기다릴 수있는 방법이 있는지 확인하기 위해 몇 초마다 폴링해야합니까? 이것은 내가 작업중 인 PHP 프로젝트이지만 루비 또는 언어에 구애받지 않고 자유롭게 대답하십시오.
답변:
당신이 생각하는 것은 방아쇠처럼 들립니다. MongoDB는 트리거를 지원하지 않지만 일부 사람들은 몇 가지 트릭을 사용하여 "자신을 굴 렸습니다". 여기서 핵심은 oplog입니다.
복제 세트에서 MongoDB를 실행하면 모든 MongoDB 작업이 작업 로그 (oplog)에 기록됩니다. oplog는 기본적으로 데이터 수정 사항의 실행 목록입니다. 복제본이 oplog의 변경 사항을 청취하고 변경 사항을 로컬로 적용하여 기능을 설정합니다.
익숙한가요?
여기에서 전체 프로세스를 자세히 설명 할 수는 없지만 여러 페이지의 문서이지만 필요한 도구를 사용할 수 있습니다.
oplog에 대한 일부 글쓰기- 간단한 설명
- 컬렉션의 레이아웃local
(oplog를 포함)
테일러 블 커서 를 활용하는 것도 좋습니다 . 이를 통해 폴링 대신 변경 사항을 청취 할 수 있습니다. 복제는 테일러 블 커서를 사용하므로 지원되는 기능입니다.
--replSet
옵션을 사용 하여 서버를 시작할 수 있으며 서버를 만들거나 채 웁니다 oplog
. 2 차 없이도. 이것이 DB의 변화를 "듣기"위한 유일한 방법입니다.
MongoDB를이 이른바 가지고 capped collections
와 tailable cursors
그 청취자에게 푸시 데이터에 MongoDB를 할 수 있습니다.
A capped collection
는 기본적으로 고정 된 크기의 컬렉션이며 삽입 만 허용합니다. 다음은 하나를 만드는 모습입니다.
db.createCollection("messages", { capped: true, size: 100000000 })
루비
coll = db.collection('my_collection')
cursor = Mongo::Cursor.new(coll, :tailable => true)
loop do
if doc = cursor.next_document
puts doc
else
sleep 1
end
end
PHP
$mongo = new Mongo();
$db = $mongo->selectDB('my_db')
$coll = $db->selectCollection('my_collection');
$cursor = $coll->find()->tailable(true);
while (true) {
if ($cursor->hasNext()) {
$doc = $cursor->getNext();
print_r($doc);
} else {
sleep(1);
}
}
파이썬 ( Robert Stewart)
from pymongo import Connection
import time
db = Connection().my_db
coll = db.my_collection
cursor = coll.find(tailable=True)
while cursor.alive:
try:
doc = cursor.next()
print doc
except StopIteration:
time.sleep(1)
펄 ( 최대 )
use 5.010;
use strict;
use warnings;
use MongoDB;
my $db = MongoDB::Connection->new;
my $coll = $db->my_db->my_collection;
my $cursor = $coll->find->tailable(1);
for (;;)
{
if (defined(my $doc = $cursor->next))
{
say $doc;
}
else
{
sleep 1;
}
}
Ruby / Node.js 학습서-MongoDB 제한 콜렉션의 삽입을 청취하는 애플리케이션 작성을 안내합니다.
MongoDB 3.6부터 Change Streams라는 새로운 알림 API가 있으며이를 사용할 수 있습니다. 예를 보려면 이 블로그 게시물을 참조하십시오 . 그것의 예 :
cursor = client.my_db.my_collection.changes([
{'$match': {
'operationType': {'$in': ['insert', 'replace']}
}},
{'$match': {
'newDocument.n': {'$gte': 1}
}}
])
# Loops forever.
for change in cursor:
print(change['newDocument'])
* 편집 : 나는 이것을하는 방법에 대한 기사를 썼다 https://medium.com/riow/mongodb-data-collection-change-85b63d96ff76
mongodb 3.6 의 새로운 기능 https://docs.mongodb.com/manual/release-notes/3.6/ 2018/01/10
$ mongod --version
db version v3.6.2
changeStreams 를 사용 하려면 데이터베이스가 복제 세트 여야합니다
복제 세트에 대한 자세한 내용 : https://docs.mongodb.com/manual/replication/
데이터베이스는 기본적으로 " 독립형 "입니다.
독립형을 복제본 세트로 변환하는 방법 : https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/
다음 예제 는 이것을 사용하는 방법에 대한 실용적인 응용 프로그램입니다.
* 노드 전용.
/* file.js */
'use strict'
module.exports = function (
app,
io,
User // Collection Name
) {
// SET WATCH ON COLLECTION
const changeStream = User.watch();
// Socket Connection
io.on('connection', function (socket) {
console.log('Connection!');
// USERS - Change
changeStream.on('change', function(change) {
console.log('COLLECTION CHANGED');
User.find({}, (err, data) => {
if (err) throw err;
if (data) {
// RESEND ALL USERS
socket.emit('users', data);
}
});
});
});
};
/* END - file.js */
유용한 링크 :
https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set
https://docs.mongodb.com/manual/tutorial/change-streams-example
https://docs.mongodb.com/v3.6/tutorial/change-streams-example
http://plusnconsulting.com/post/MongoDB-Change-Streams
MongoDB 버전 3.6에는 이제 트리거 / 알림과 유사한 사용 사례를 허용하는 OpLog 위에 API 인 변경 스트림이 포함되어 있습니다.
다음은 Java 예제에 대한 링크입니다. http://mongodb.github.io/mongo-java-driver/3.6/driver/tutorials/change-streams/
NodeJS 예제는 다음과 같습니다.
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:22000/MyStore?readConcern=majority")
.then(function(client){
let db = client.db('MyStore')
let change_streams = db.collection('products').watch()
change_streams.on('change', function(change){
console.log(JSON.stringify(change));
});
});
또는 표준 Mongo FindAndUpdate 메소드를 사용하고 콜백 내에서 콜백이 실행될 때 노드에서 EventEmitter 이벤트를 발생시킬 수 있습니다.
이 이벤트를 수신하는 응용 프로그램 또는 아키텍처의 다른 부분은 업데이트 및 관련 데이터도 함께 알림을받습니다. 이것은 몽고의 알림을 얻는 간단한 방법입니다.
이러한 답변 중 다수는 새로운 기록 만 제공하며 업데이트가 아니거나 매우 비효율적입니다.
이를 수행 할 수있는 신뢰할 수 있고 성능이 좋은 유일한 방법은 로컬 db : oplog.rs 콜렉션에 꼬리 커서를 작성하여 MongoDB에 대한 모든 변경 사항을 가져오고 원하는 작업을 수행하는 것입니다. (MongoDB는 복제를 지원하기 위해 내부적으로 어느 정도까지 수행합니다!)
oplog에 포함 된 내용에 대한 설명 : https://www.compose.com/articles/the-mongodb-oplog-and-node-js/
oplog로 수행 할 수있는 작업에 대한 API를 제공하는 Node.js 라이브러리 예 : https://github.com/cayasso/mongo-oplog
MongoDB Stitch 라는 멋진 서비스 세트가 있습니다 . 스티치 기능 / 트리거를 살펴보십시오 . 이는 클라우드 기반 유료 서비스 (AWS)입니다. 귀하의 경우 삽입에서 자바 스크립트로 작성된 사용자 정의 함수를 호출 할 수 있습니다.
여기 에서 찾을 수있는 작동중인 Java 예제가 있습니다 .
MongoClient mongoClient = new MongoClient();
DBCollection coll = mongoClient.getDatabase("local").getCollection("oplog.rs");
DBCursor cur = coll.find().sort(BasicDBObjectBuilder.start("$natural", 1).get())
.addOption(Bytes.QUERYOPTION_TAILABLE | Bytes.QUERYOPTION_AWAITDATA);
System.out.println("== open cursor ==");
Runnable task = () -> {
System.out.println("\tWaiting for events");
while (cur.hasNext()) {
DBObject obj = cur.next();
System.out.println( obj );
}
};
new Thread(task).start();
열쇠는 여기에 주어진 QUERY OPTIONS 입니다.
매번 모든 데이터를로드 할 필요가없는 경우 찾기 쿼리를 변경할 수도 있습니다.
BasicDBObject query= new BasicDBObject();
query.put("ts", new BasicDBObject("$gt", new BsonTimestamp(1471952088, 1))); //timestamp is within some range
query.put("op", "i"); //Only insert operation
DBCursor cur = coll.find(query).sort(BasicDBObjectBuilder.start("$natural", 1).get())
.addOption(Bytes.QUERYOPTION_TAILABLE | Bytes.QUERYOPTION_AWAITDATA);
실제로 출력을 보는 대신 몽구스 스키마 에서 제공 한 미들웨어를 사용하여 새로운 내용을 삽입 할 때 통지를받지 못하는 이유
새 문서를 삽입하는 이벤트를 포착하고 삽입이 완료된 후 무언가를 수행 할 수 있습니다.